Skip to main content

web3-triage-report

Bug triage validation system, Immunefi report format, and 20 real paid bounty examples dissected. Use this when validating a finding before submitting, writing an Immunefi report, checking if a bug is actually valid, or studying real examples of paid vulnerabilities.

Zur Installation springen

Quellinformationen

Repository
tradecatlabs/vibe-coding-cn
Letzte Quellaktivität
12. September 2026 um 13:03
Erkannte Sprache von SKILL.md
Englisch
Sterne
16.256
Forks
1.645

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
web3-triage-report
description
Bug triage validation system, Immunefi report format, and 20 real paid bounty examples dissected. Use this when validating a finding before submitting, writing an Immunefi report, checking if a bug is actually valid, or studying real examples of paid vulnerabilities.
# TRIAGE, REPORT WRITING & REAL EXAMPLES --- ## PART 1: TRIAGE ### THE 7-QUESTION GATE Ask these IN ORDER before writing a single word of your report. ONE wrong answer = STOP and move on. --- #### Q1: Can an attacker use this RIGHT NOW, step by step? Complete this template: ``` 1. Setup: [what I need] 2. Call: [exact function, exact params] 3. Result: [what I have that I didn't have before] 4. Cost: [gas + capital] 5. ROI: [profit / cost ratio] ``` If you cannot complete steps 2 and 3 with specific function calls: **KILL IT.** --- #### Q2: Is the impact in the program's accepted impact list? Go to the Immunefi program page. Find "Impacts in Scope." Match your bug to one of these EXACTLY. Example impact tiers: - "Direct theft of any user funds" — Critical - "Permanent freezing of funds" — Critical - "Protocol insolvency" — Critical - "Theft of unclaimed yield" — High - "Permanent freezing of unclaimed yield" — High - "Temporary freezing of funds" — High - "Smart contract unable to operate due to lack of token funds" — Medium - "Griefing (no profit motive, but damage to users)" — Medium - "Contract fails to deliver promised returns, but doesn't lose value" — Low If your bug does not match any impact in scope: **KILL IT.** --- #### Q3: Is the root cause in an in-scope contract? Confirm the exact deployed address is in scope on the program page. If the bug is in Aave, Uniswap, OpenZeppelin, or any external dependency: **KILL IT.** --- #### Q4: Does it require admin/privileged access? "Admin can drain funds" = centralization risk = **KILL IT.** "Admin can set parameter X which under condition Y creates DoS" = borderline. Salvage path: can the bug trigger WITHOUT the admin doing anything unusual? - If yes: valid - If no: likely invalid (requires admin mistake — almost always out of scope) --- #### Q5: Is this already known/acknowledged in prior audits? Find the audit reports for the protocol. Search for "Risk Accepted," "Acknowledged," "Won't Fix." If your bug matches a known finding: **KILL IT.** Edge case: if acknowledged finding + NEW code around it creates a new attack path → that is a new bug, not the acknowledged one. Must prove the new path. --- #### Q6: Is the economic attack viable? ``` Attacker spends: gas + capital Attacker gains: tokens stolen or protocol damaged If profit < cost: KILL IT. ``` Example: - DoS via dust harvest: costs 1 wei USDC + gas, disables yield for $81K TVL → VIABLE. - Withdraw-fee arbitrage: fee (0.1%) > diluted yield from attack → NOT profitable → KILL IT. --- #### Q7: Is this already public? - Is it on social media or in a disclosed report? - Was it previously submitted and disclosed? - Is the "sensitive" data visible in the UI already? If yes: **KILL IT.** --- ### THE SEVERITY MATRIX Score = Impact × Likelihood × Exploitability (each 1–3) | | Impact=1 (info leak) | Impact=2 (partial) | Impact=3 (theft/freeze) | |--|--|--|--| | L=1 E=1 | 1 (Info) | 2 (Low) | 3 (Low) | | L=2 E=2 | 4 (Medium) | 8 (High) | 12 (High) | | L=3 E=3 | 9 (High) | 18 (Critical) | 27 (Critical) | **Rule: When borderline, round DOWN. Over-classification destroys credibility.** --- ### THINK LIKE AN ATTACKER TEMPLATE Before writing your report, fill in this attack scenario: ``` Protocol: [name] Target contract: [address + function] Preconditions: [what state must exist?] Attack sequence: 1. Attacker calls [exact function] with [exact params] 2. [What happens in the contract] 3. [What state changes] 4. Attacker ends up with: [X more tokens / broken state / DoS] Total cost: [gas estimate + capital requirement] Total gain: [$X stolen / $Y TVL frozen] Viable? [yes/no + reason] ``` If you can't fill in steps 1–4 with specific values, the bug is not ready to submit. --- ### THINK LIKE A TRIAGER CHECKLIST A triager reviewing your report will immediately check: - [ ] Does the title match an accepted impact? - [ ] Is the vulnerable function clearly identified (file + line)? - [ ] Is the root cause explained (not just "there is a bug")? - [ ] Is there comparison evidence ("function A has this, function B doesn't")? - [ ] Does the PoC run without errors? - [ ] Is the severity appropriate to the actual impact? - [ ] Is the bug already in the known issues list? - [ ] Does the fix make sense (proves you understand the root cause)? If your report can't pass this checklist: revise before submitting. --- ### SEVERITY DOWNGRADE TRIGGERS | Condition | Severity drops | |-----------|---------------| | Requires specific admin configuration | -1 level | | Impact limited to a small subset of users | -1 level | | Requires long time window (>24h) to exploit | -1 level | | Protocol can detect and pause before loss | -1 level | | Impact is yield loss, not principal loss | -1 level | | Bug is theoretical with no practical attack | Down to Info | | Attack costs more than attacker gains | Invalid | --- ### VALID vs INVALID COMPARISON TABLE | Bug | Valid? | Reason | |-----|--------|--------| | DISTRIBUTOR_ROLE never granted → claimFor() permanently uncallable | **Valid (Medium)** | Deployment bug, not admin action, real impact on users | | `- 1` strands 1 wei per harvest | **Valid (Low/Info)** | Real, quantified, honest about minor impact | | Front-run harvest (acknowledged in prior audit) | **Invalid** | Known issue = instant rejection | | Admin can change fee to 100% | **Invalid** | Centralization risk = almost always OOS | | Harvest DoS via dust (requires admin misconfiguration) | **Borderline** | Must prove it triggers without unusual admin action | | ecrecover returns address(0) = anyone can pass | **Valid (Critical)** | No preconditions, direct theft | | Contract uses spot price oracle | **Valid (High/Critical)** | Flash loan manipulation, well-documented impact | | Missing slippage parameter | **Valid (Medium)** | MEV sandwich possible, quantifiable loss | | GraphQL introspection enabled | **Invalid** | Info disclosure only, no exploitation path | | Missing HSTS header | **Invalid** | Always rejected | --- ### THE VALIDITY RATIO Immunefi tracks your submission:triage ratio. High invalid submission rate → your future reports get lower priority. **Target: 70%+ valid submissions.** Better to submit 3 valid bugs than 10 invalid ones. A low-severity honest submission is better for your ratio than an overclaimed invalid one. --- ## PART 2: REPORT WRITING ### THE WINNING FORMULA 1. **Title** = [Exact function] + [root cause] + [quantified impact] 2. **Comparison evidence** = "Function A has X, Function B doesn't" 3. **Attack path** = numbered steps, each with exact function call 4. **Quantified impact** = "$X stolen" or "X% yield diluted" 5. **PoC output** = actual console.log numbers, not just "test passes" 6. **1-line fix** = proves you understand the root cause --- ### IMMUNEFI REPORT TEMPLATE (Complete) ```markdown ## [Exact function in ContractName] — [root cause in 10 words] leads to [quantified impact] ### Example title: "_performHarvest() in Ern.sol subtracts hardcoded 1 wei causing reward token permanent lockup across all harvests" --- ## Summary [2-3 sentences maximum. What is the bug, where is it, what does it enable.] The `_performHarvest()` function in `Ern.sol` subtracts a hardcoded `1` from `userRewards` without distributing or accounting for the remainder. This causes 1 wei of reward token to be permanently locked in the contract after every harvest, and — more critically — causes a revert when Uniswap returns 0 output for dust-amount swaps, permanently freezing the harvest function. --- ## Vulnerability Details **Contract:** `Ern.sol` **Function:** `_performHarvest()`, line 187 **Type:** Arithmetic error / Incomplete path **Vulnerable Code:** ```solidity uint256 protocolFee = (rewardReceived * harvestFee) / 10000; uint256 userRewards = rewardReceived - protocolFee - 1; // ← BUG: hardcoded -1 if (protocolFee > 0) REWARD_TOKEN.safeTransfer(owner(), protocolFee); if (totalSharesSupply > 0) { cumulativeRewardPerShare += (userRewards * 1e18) / totalSharesSupply; } ``` **Comparison Evidence:** Function `claimYield()` at line 120 correctly handles zero-amount cases. `_performHarvest()` at line 187 does not account for the stranded `1 wei` remainder, creating a silent fund loss on every harvest. **Root Cause:** The `- 1` subtraction creates a permanent accounting gap. The 1 wei: - Is NOT sent to the protocol fee recipient (owner) - Is NOT distributed to users via `cumulativeRewardPerShare` - Remains locked in the contract indefinitely with no recovery mechanism **Attack Path (numbered, each step is a specific function call):** 1. Owner sets `minYieldAmount` to minimum (1 * 10^6 = 1 USDC) 2. `harvestTimePeriod` passes (24 hours by default) 3. Yield accrued: 1 wei of aUSDC above totalSupply 4. `canHarvest()` returns `true` (time condition satisfied) 5. Harvester calls `harvest(0)` with `minOut = 0` 6. `yieldAmount = 1` → Aave withdraws 1 wei USDC 7. Uniswap `exactInputSingle(1 wei USDC → WBTC)` returns `0` output 8. `rewardReceived = 0` 9. `userRewards = 0 - 0 - 1 = type(uint256).max` ← ARITHMETIC UNDERFLOW 10. Transaction reverts. All future harvests permanently blocked. --- ## Impact **Severity:** High **Category:** Temporary freezing of funds **Quantified Impact:** - ernUSDC TVL: $69,300 - ernUSDT TVL: $12,000 - All accrued wBTC yield frozen for all depositors - Recovery requires owner intervention or protocol upgrade **Preconditions:** [list any setup conditions required] --- ## Proof of Concept [Working Foundry test that runs with forge test -vvv] [Must include console.log output showing actual numbers] [Must compile and pass cleanly] **Expected Output:** ``` [PASS] testHarvestDoS() Logs: canHarvest: true yieldAmount: 1 harvest() REVERTS: arithmetic underflow confirmed All future harvests blocked until owner intervenes ``` --- ## Recommended Fix **Option 1 — Remove the unexplained `-1`:** ```solidity // Before: uint256 userRewards = rewardReceived - protocolFee - 1; // After: uint256 userRewards = rewardReceived - protocolFee; ``` **Option 2 — Guard against zero rewardReceived:** ```solidity if (rewardReceived == 0) { lastHarvest = block.timestamp; return; } ``` --- ## References - Vulnerable code: `ContractName.sol` line X (deployed at `0x...`) - Related prior audit finding (if relevant): [explain why yours is DIFFERENT] - CWE/weakness class: [e.g., CWE-191: Integer Underflow] ``` --- ### TITLE FORMULA ``` [ROOT CAUSE] in [function name] allows [WHO] to [IMPACT] ``` Examples: - `Missing access control in setPassword() allows anyone to change the stored password` - `Reentrancy in refund() enables attacker to drain all ETH before state update` - `Spot price oracle in getPrice() enables flash loan manipulation of exchange rates` - `_performHarvest() subtracts hardcoded 1 wei causing permanent harvest DoS when Uniswap returns 0` --- ### IMPACT SELECTION GUIDE Match your finding to one of these Immunefi tiers (program-specific — always verify): | Impact | Tier | Typical payout range | |--------|------|---------------------| | Direct theft of user funds (no limit) | Critical | $50K–$10M | | Permanent freezing of funds | Critical | $50K–$10M | | Protocol insolvency | Critical | $50K–$10M | | Theft of unclaimed yield | High | $10K–$100K | | Permanent freezing of unclaimed yield | High | $10K–$100K | | Temporary freezing of funds (>1 hour) | High | $5K–$50K | | Contract can't operate due to lack of funds | Medium | $2K–$10K | | Griefing (damage, no profit motive) | Medium | $2K–$10K | | Contract fails to deliver promised returns | Low | $500–$2K | --- ### PoC REQUIREMENTS A PoC that wins bounties must: 1. Be a working Foundry test (`forge test -vvv` passes) 2. Fork mainnet at a specific block number 3. Use real deployed contract addresses 4. Show console.log output with actual dollar amounts or token counts 5. Be reproducible by the triager with a single command A PoC that gets rejected: - "Test passes" with no meaningful assertion - Compilation errors - Wrong mainnet addresses - No fork — just unit tests with mocks - No quantification of impact --- ### COMMON REJECTION REASONS 1. **Vague impact:** "Could potentially cause loss of funds" → Always quantify in USD 2. **No comparison evidence:** "This is missing" without showing what sibling function has it 3. **PoC that doesn't run:** Compilation errors, wrong addresses → test before submitting 4. **Wrong severity:** Overclassifying → damages credibility for future reports 5. **Known issue not checked:** Submitting what's already in the audit report → instant reject 6. **No fix provided:** Shows you don't fully understand root cause 7. **Multiple variants of same bug:** Submit ONE report per root cause 8. **Missing preconditions:** Listing an admin action as if it's freely exploitable --- ### WHAT TRIAGERS ACTUALLY WANT TO SEE From analyzing winning reports across Immunefi competitions: - **Comparison evidence is the #1 differentiator.** "Function X has guard Y, Function Z doesn't" is more compelling than just saying "Function Z is missing guard Y." - **Numbers matter more than words.** "$69,300 TVL frozen" > "significant funds at risk." - **The fix proves understanding.** A 1-line fix that addresses root cause > a 10-line defensive patch. - **Attack cost matters.** "1 wei USDC + gas" > "substantial capital required." - **Preconditions must be honest.** Triagers will test the scenario. If you omit that it requires admin action, they will find it and reject. --- ## PART 3: REAL EXAMPLES 20 paid bounty reports dissected — pattern, technique, key insight. --- ### 1. Wormhole — $10M (Uninitialized Proxy) **Protocol:** Wormhole bridge **Payout:** $10,000,000 **Bug class:** Upgrade patterns / Access control **Root cause:** UUPS proxy implementation contract missing `_disableInitializers()` in constructor. Attacker called `initialize()` directly on the implementation, became guardian, upgraded proxy to malicious contract. **What the hunter did:** Called `implementation()` on the UUPS proxy → got impl address → called `initialize()` directly on impl → became guardian → upgraded proxy.
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen