--- name: report-writing description: Bug bounty report writing for H1/Bugcrowd/Intigriti/Immunefi — report templates, human tone guidelines, impact-first writing, CVSS 3.1 scoring, title formula, impact statement formula, severity decision guide, downgrade counters, pre-submit checklist. Use after validating a finding and before submitting. Never use "could potentially" — prove it or don't report. --- # REPORT WRITING Impact-first. Human tone. No theoretical language. Triagers are people. --- ## THE MOST IMPORTANT RULE > **Never use "could potentially" or "could be used to" or "may allow".** > Either it does the thing or it doesn't. If you haven't proved it, don't claim it. ``` BAD: "This vulnerability could potentially allow an attacker to access user data." GOOD: "An attacker can access any user's order history by changing the user_id parameter to the target user's ID. I confirmed this using two test accounts: attacker@test.com (ID 123) successfully retrieved victim@test.com (ID 456) orders, including their shipping address and payment method last 4 digits." ``` ## PERSISTENCE RULE Every report-writing session must leave a complete finding folder on disk. Save the report draft, pre-submit checklist, references, downgrade counters, and final submission note under `findings/-/`. Never rely on terminal or tmux scrollback for content the hunter needs later. Minimum files: ```text findings/-/ ├── hackerone-report.md # or bugcrowd-report.md / intigriti-report.md / immunefi-report.md ├── submission-notes.md # final checklist, references, caveats, next action └── evidence/ # screenshots, curl output, response bodies when available ``` If `tools/validate.py` already wrote `submission-notes.md`, append/update it instead of creating a duplicate. --- ## TITLE FORMULA ``` [Bug Class] in [Exact Endpoint/Feature] allows [attacker role] to [impact] [victim scope] ``` **Good titles (specific, impact-first):** ``` IDOR in /api/v2/invoices/{id} allows authenticated user to read any customer's invoice data Missing auth on POST /api/admin/users allows unauthenticated attacker to create admin accounts Stored XSS in profile bio field executes in admin panel — allows privilege escalation SSRF via image import URL parameter reaches AWS EC2 metadata service Race condition in coupon redemption allows same code to be used unlimited times ``` **Bad titles (vague, useless to triager):** ``` IDOR vulnerability found Broken access control XSS in user input Security issue in API Unauthorized access to user data ``` --- ## HACKERONE REPORT TEMPLATE ```markdown ## Summary [One paragraph: what the bug is, where it is, what an attacker can do. Be specific. Include: endpoint, method, parameter, data exposed, required access level.] Example: "The `/api/users/{user_id}/orders` endpoint does not verify that the authenticated user owns the requested user_id. An attacker can enumerate any user's order history, including PII (email, address, phone) and purchase history, by incrementing the user_id parameter. No privileges beyond a standard free account are required." ## Vulnerability Details **Vulnerability Type:** IDOR / Broken Object Level Authorization **CVSS 3.1 Score:** 6.5 (Medium) — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N **Affected Endpoint:** GET /api/users/{user_id}/orders ## Steps to Reproduce **Environment:** - Attacker account: attacker@test.com, user_id = 123 - Victim account: victim@test.com, user_id = 456 - Target: https://target.com **Steps:** 1. Log in as attacker@test.com, obtain Bearer token 2. Send the following request: ``` GET /api/users/456/orders HTTP/1.1 Host: target.com Authorization: Bearer ATTACKER_TOKEN_HERE ``` 3. Observe response: ```json { "orders": [ {"id": 789, "items": [...], "email": "victim@test.com", "address": "123 Main St..."} ] } ``` The response contains victim's full order history and PII despite being requested by a different user. ## Impact An authenticated attacker can enumerate all user orders by iterating user_id values. This exposes: full name, email, shipping address, purchase history, and payment method (last 4). With ~100K users, this represents a mass PII breach affecting all registered users. Exploitation requires only a free account and takes minutes with a simple loop. ## Recommended Fix Add server-side ownership verification: ```python if order.user_id != current_user.id: raise Forbidden() ``` ## Supporting Materials [Screenshot showing attacker's session returning victim's order data] [Video walkthrough if available] ``` --- ## BUGCROWD REPORT TEMPLATE ```markdown # [IDOR] User order history accessible without authorization via /api/users/{id}/orders **VRT Category:** Broken Access Control > IDOR > P2 ## Description [Same impact-first paragraph as HackerOne summary] ## Steps to Reproduce [Same structured steps — exact HTTP requests, exact responses] ## Proof of Concept [Screenshot/video showing the actual impact] ## Expected vs Actual Behavior **Expected:** 403 Forbidden when user_id does not match authenticated user **Actual:** 200 OK with victim's full order data ## Severity Justification P2 (High) — Direct read access to other users' PII. Affects all user accounts. No user interaction required. Exploitable by any authenticated user. Automated enumeration could exfil all [N] user records in minutes. ## Remediation Add ownership verification: `if order.user_id != current_user.id: raise 403` ``` --- ## INTIGRITI REPORT TEMPLATE ```markdown # [Bug Class]: [Exact Impact] in [Endpoint/Feature] ## Description [Impact-first paragraph. Start with what an attacker can do, not with how you found it. Include: endpoint, method, parameter, data exposed, required privileges.] ## Steps to Reproduce **Environment:** - Attacker: email=attacker@test.com (standard account, no special role) - Victim: email=victim@test.com - Tested: [date] **Reproduction steps:** 1. [Login as attacker / visit URL / send request] 2. Send the following HTTP request: \```http METHOD /endpoint HTTP/1.1 Host: target.com Authorization: Bearer ATTACKER_TOKEN Content-Type: application/json {"param": "victim_id_here"} \``` 3. Observe response contains victim's private data: \```json {"email": "victim@test.com", "address": "123 Main St", ...} \``` ## Impact [Specific, quantified impact. What data, how many users, what can attacker do.] CVSS 3.1 Score: X.X ([Severity]) — AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N ## Remediation [1-3 sentence concrete fix. Include code if helpful.] ## Attachments [Screenshot or Loom video showing the impact — Intigriti triagers prefer video for complex bugs] ``` **Intigriti-specific notes:** - Title format: `[Bug Class]: [One-line impact]` (no formula required, but keep it specific) - Severity is set by you: Critical/High/Medium/Low/Exceptional - CVSS 3.1 is standard (CVSS 4.0 also accepted on newer programs) - PoC video is valued much more than screenshot alone — record with Loom - Safe harbor: Intigriti enforces it, be comfortable going slightly aggressive with testing --- ## IMMUNEFI REPORT TEMPLATE ```markdown # [Bug Class] — [Protocol Name] — [Severity] ## Summary [One paragraph with: root cause, affected function, economic impact, attack cost. Include numbers where possible: "attacker can drain $X in Y transactions."] ## Vulnerability Details **Contract:** `VulnerableContract.sol` **Function:** `claimRedemption()` **Bug Class:** Accounting State Desynchronization **Severity:** Critical ### Root Cause [Exact code snippet showing the vulnerable code with comments] ## Proof of Concept ```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; // Foundry PoC — run: forge test --match-test test_exploit -vvvv contract ExploitTest is Test { // ... full working exploit } ``` ## Impact [Quantified: "Attacker can drain X% of TVL = $Y at current rates. Requires $Z gas. Attack is repeatable."] ## Recommended Fix [Specific code change with before/after] ``` --- ## CVSS 3.1 QUICK SCORING ### Formula ``` CVSS = f(AV, AC, PR, UI, S, C, I, A) ``` ### Metric Quick Picks | Metric | Value | Weight | When | |---|---|---|---| | **Attack Vector (AV)** | Network | +0.85 | Via internet | | | Local | +0.55 | Local access needed | | **Attack Complexity (AC)** | Low | +0.77 | Repeatable | | | High | +0.44 | Race/timing needed | | **Privileges Required (PR)** | None | +0.85 | No login | | | Low | +0.62 | Regular user account | | | High | +0.27 | Admin account | | **User Interaction (UI)** | None | +0.85 | No victim action | | | Required | +0.62 | Victim must click | | **Scope (S)** | Changed | higher | Affects browser/OS/other | | | Unchanged | lower | Stays in app | | **Confidentiality (C)** | High | +0.56 | All data exposed | | | Low | +0.22 | Limited data | | **Integrity (I)** | High | +0.56 | Can modify any data | | **Availability (A)** | High | +0.56 | Crashes service | ### Typical Scores by Bug Class | Bug | Typical CVSS | Severity | |---|---|---| | IDOR (read PII) | 6.5 | Medium | | IDOR (write/delete) | 7.5 | High | | Auth bypass → admin | 9.8 | Critical | | Stored XSS (any user) | 5.4–8.8 | Med–High | | SQLi (data exfil) | 8.6 | High | | SSRF (cloud metadata) | 9.1 | Critical | | Race condition (double spend) | 7.5 | High | | GraphQL auth bypass | 8.7 | High | | JWT none algorithm | 9.1 | Critical | --- ## SEVERITY DECISION GUIDE ### Critical (P1) - Full account takeover of any user without interaction - Remote code execution - SQLi with ability to dump/modify entire DB - Auth bypass to admin panel - SSRF to cloud metadata → IAM credentials exfil ### High (P2) - Mass PII exposure (email, phone, SSN, payment data) - Privilege escalation from user to admin - SSRF reaching internal services (data returned) - Stored XSS executing for all users of sensitive feature - Payment bypass / financial loss without limit ### Medium (P3) - IDOR on specific user's non-critical data - XSS on low-sensitivity page requiring victim interaction - CSRF on important but non-critical action - Rate limit bypass on OTP (with effort demonstrated) ### Low (P4) - Information disclosure (non-sensitive, no PII) - Clickjacking on sensitive action WITH working PoC - CORS on limited data --- ## SEVERITY SELF-ASSESSMENT Each YES raises severity: ``` 1. Exposes PII / health / financial data of other users? → +1 severity 2. Allows account takeover or privilege escalation? → +2 severity 3. Requires ZERO user interaction from victim? → +1 severity 4. Affects ALL users (not specific condition)? → +1 severity 5. Remotely exploitable with no internal network access? → baseline for High+ ``` --- ## DOWNGRADE COUNTERS | Program Says | Counter With | |---|---| | "Requires authentication" | "Attacker needs only a free account — no special role or permission" | | "Limited impact" | "Affects [N] users / exposes [PII type] / $[amount] at risk" | | "Already known" | "Show me the report number — I searched hacktivity and found none" | | "By design" | "Show me the documentation stating this is intended behavior" | | "Low CVSS" | "CVSS doesn't capture business impact — attacker can extract [X] in [Y] minutes" | | "Not exploitable" | "Here is the exact response showing victim's data returned to attacker session" | --- ## THE 60-SECOND PRE-SUBMIT CHECKLIST ``` [ ] Title follows formula: [Class] in [endpoint] allows [actor] to [impact] [ ] First sentence states exact impact in plain English [ ] Steps to Reproduce has exact HTTP request (copy-paste ready) [ ] Response showing the bug is included (screenshot or JSON body) [ ] Two test accounts used — not just one account testing itself [ ] CVSS score calculated and included [ ] Recommended fix is 1-2 sentences (not a lecture) [ ] No typos in endpoint paths or parameter names [ ] Report is < 600 words — triagers skim long reports [ ] Severity claimed matches impact described — don't overclaim [ ] Never used "could potentially" or "may allow" [ ] PoC is reproducible by triager from a fresh state ``` --- ## CVSS 4.0 QUICK REFERENCE (newer programs) CVSS 4.0 replaced CVSS 3.1 in November 2023. Some newer programs require it. ### Key Differences from CVSS 3.1 | Metric | CVSS 3.1 | CVSS 4.0 | |---|---|---| | Attack Vector | Network/Adjacent/Local/Physical | Same | | Attack Complexity | Low/High | Low/High | | **NEW**: Attack Requirements | (didn't exist) | None/Present (replaces some PR/UI) | | Privileges Required | None/Low/High | Same | | User Interaction | None/Required | None/Passive/Active | | Scope | Unchanged/Changed | REMOVED | | **NEW**: Sub-Impact metrics | (didn't exist) | Vulnerable/Subsequent system impact | ### CVSS 4.0 Score Examples | Finding | CVSS 4.0 Score | Vector | |---|---|---| | Unauthenticated RCE | 10.0 | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H | | IDOR read PII, auth required | 6.9 | CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N | | Stored XSS, admin views it | 8.2 | CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:N/SC:H/SI:H/SA:N | | SSRF → cloud metadata | 8.7 | CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:H/SI:H/SA:N | ### Quick CVSS 4.0 Calculator ``` Use: https://www.first.org/cvss/calculator/4.0 Key fields: VC/VI/VA = Vulnerable System Confidentiality/Integrity/Availability SC/SI/SA = Subsequent System (downstream impact) AT = None (no special condition) | Present (race/specific config needed) UI = None | Passive (victim visits URL) | Active (victim takes explicit action) ``` **Practical rule**: If program uses CVSS 4.0 and you don't know the vector, use the calculator and include the full string starting with `CVSS:4.0/AV:...`. Programs cannot dispute a valid vector string. --- ## HUMAN TONE GUIDELINES **Write to a person, not a system:** - Triagers are tired. Get to the impact in sentence 1. - Use "I" not "the researcher" — you found it, own it - Short paragraphs, bullet points for steps - Hyperlink relevant docs if needed **Escalation language (when payout is being downgraded):** ``` "This vulnerability does not require any special privileges — only a free account." "The exposed data includes [PII type], which is subject to GDPR requirements." "An attacker can automate this with a simple loop — all [N] records in minutes." "This is exploitable externally without network access to any internal system." "The impact is equivalent to a full data breach of [feature/data type]." ``` **Avoid:** - Jargon the triager might not know - 5-paragraph explanations of what IDOR is (they know) - Theoretical chains ("could be combined with X to...") - Passive voice ("it was observed that...") - Qualifying language ("seems to," "appears to") --- ## STEPS TO REPRODUCE FORMAT (triager-optimized) ```markdown **Setup:** - Account A (attacker): email=attacker@test.com, ID=111 - Account B (victim): email=victim@test.com, ID=222 - Both created via normal registration — no special access **Steps:** 1. Log in as Account A 2. Send this request (replace `111` with victim ID `222`): \``` GET /api/v2/resource/222 HTTP/1.1 Host: target.com Authorization: Bearer ACCOUNT_A_TOKEN \``` 3. Response contains Account B's private data: \```json {"id": 222, "email": "victim@test.com", "name": "Victim User", "address": "..."} \``` **Expected:** 403 Forbidden **Actual:** 200 OK with victim's private data ```