🌳 Advanced ⏱️ 60 min

Your First Audit: A Step-by-Step Guide

Your first competitive audit will be humbling. You will find fewer bugs than you expected, miss findings that seem obvious in the post-contest analysis, and possibly earn nothing if the contest is highly competitive. This is normal and expected — every top auditor went through exactly this. The goal of your first audit is not to earn money. It is to learn the process, calibrate your abilities, and build momentum. This lesson gives you the exact framework to make that first audit as productive as possible.

📖 Realistic Expectations for Your First Audit

Top auditors on Code4rena and Sherlock typically found zero to two valid findings in their first contest. Low and Medium findings are entirely normal for a beginner. A single valid High finding in your first audit would be an excellent result. The distribution of earnings is extremely top-heavy — the top 5% of auditors earn 80% of rewards. Getting into that bracket takes 12-24 months of consistent effort, not one lucky contest.

Choosing Your First Contest

🔍 Contest Selection Criteria for Beginners
// Green flags (choose this contest): // - Codebase size: < 1000 SLOC (Source Lines of Code) // - Protocol type you have studied: lending, AMM, ERC20 — not a novel mechanism // - Good documentation: README, NatSpec, protocol docs available // - Foundry-based: easier to write PoCs // - Medium prize pool ($20K-$100K): competitive but not overwhelming // - Duration: 7-14 days (not 3 days — you need time to learn the codebase) // Red flags (skip this contest as a beginner): // - Novel mechanisms you have never seen (ZK circuits, custom VMs, L2 sequencers) // - >5000 SLOC — overwhelming for first audit // - No documentation at all // - Very large prize pool ($500K+) — hundreds of experienced auditors competing // - Protocol with many external dependencies (10+ integrations) // How to find contests: // Code4rena: code4rena.com/contests — shows all active and upcoming // Sherlock: app.sherlock.xyz/audits — shows active contests // Cantina: cantina.xyz — higher bar, invite system, some open // Hats Finance: hats.finance — smaller bug bounties

Setup: Before Day 1

🔍 Pre-Contest Setup Checklist
# 1. Fork the contest repository $ git clone https://github.com/contest-org/contest-repo $ cd contest-repo # 2. Install Foundry dependencies $ forge install $ forge build # 3. Run existing tests — make sure they all pass $ forge test # If tests fail before you touch anything: note which ones, understand why # 4. Install analysis tools $ pip3 install slither-analyzer $ cargo install aderyn # 5. Count lines of code in scope $ cloc src/ --include-lang=Solidity # or: forge inspect src/Contract.sol:Contract abi | wc -l (rough estimate) # 6. Set up your notes file $ touch AUDIT_NOTES.md # Structure: Per-file sections, Leads, Findings, Questions for team # 7. Join the contest Discord channel if available # Read all pinned messages — protocol team often clarifies scope there

Day-by-Day Plan: 7-Day Contest

🔍 Day 1: Context and Orientation
// DAY 1 GOAL: Understand what the protocol does without reading Solidity // Morning (4 hours): // 1. Read the FULL README — not just the first paragraph // 2. Read all linked documentation (Gitbook, etc.) // 3. Find and read ALL prior audits // 4. Look up this protocol on Solodit — any known issues in similar protocols? // Afternoon (4 hours): // 5. Run: forge coverage --report summary (understand test coverage) // 6. Run: slither . --print human-summary (architecture overview) // 7. Draw the contract architecture on paper: // - Which contracts call which? // - Where does ETH/tokens enter and exit? // - Who is the admin? What can they do? // 8. Write your initial threat model (5-10 bullet points) // End of Day 1 deliverable: // A one-page mental model of the protocol — what it does, who uses it, // where the money is, and your top 5 suspected attack surfaces
🔍 Day 2: Automated Pass
// DAY 2 GOAL: Clear the "automated findings" backlog // Morning (4 hours): // 1. Full Slither run, save output: slither . 2>&1 | tee slither.txt // 2. For each High/Medium finding: investigate, valid or false positive? // 3. Run aderyn for a second opinion: aderyn . -o aderyn-report.md // 4. Note any valid-looking Slither findings as "leads" in AUDIT_NOTES.md // Afternoon (4 hours): // 5. Generate Slither call graph: slither . --print call-graph // 6. List ALL external/public functions — this is your work queue // 7. Mark each function: HIGH/MED/LOW priority for manual review // HIGH: transfers tokens/ETH, modifies core accounting, access control // MED: reads from external protocols, governance actions // LOW: view functions, admin parameter setters within safe bounds // 8. Order your manual review queue: HIGH functions first
🔍 Days 3-4: Deep Manual Review
// DAYS 3-4 GOAL: Methodically review all HIGH and MEDIUM priority functions // For each function in priority order: // 1. Read it once for understanding — what does it do? // 2. Apply the 5-question framework: // WHO can call this? (access control correct?) // WHEN can this be called? (time-based issues?) // WHAT state changes? (CEI pattern?) // WHAT external calls? (return values? reentrancy?) // WHAT inputs are not validated? (edge cases?) // 3. Apply token handling checks (fee-on-transfer? SafeERC20?) // 4. Check oracle usage if present // 5. Note anything suspicious — even small things // Reading tips for speed: // - Read math twice — write it out algebraically if needed // - Trace every require() — what condition triggers it? // - Follow every storage variable — where is it written? where read? // - For every external call: Ctrl+Click to the called contract
🔍 Days 5-6: PoC Development
// DAYS 5-6 GOAL: Prove each lead is exploitable, draft reports // For each "lead" in AUDIT_NOTES.md: // 1. Write a failing test that proves normal operation works // 2. Write a test that exercises the suspicious edge case // 3. Does it reproduce the suspected vulnerability? // YES: This is a finding — start the report // NO: Was your hypothesis wrong? Or just the test? // UNSURE: Spend max 2 more hours before moving on function testLead_MissingSlippageOnSwap() public { // Fork mainnet state vm.createSelectFork("mainnet"); // Setup: simulate sandwich attacker address sandwicher = makeAddr("sandwicher"); deal(address(USDC), sandwicher, 1_000_000e6); // Step 1: Sandwicher front-runs vm.prank(sandwicher); // ... buy ETH before victim ... // Step 2: Protocol executes vulnerable swap protocol.rebalance(); // calls router.swap() with amountOutMin=0 // Step 3: Sandwicher back-runs vm.prank(sandwicher); // ... sell ETH ... // Assert sandwicher profited at protocol's expense assertGt(USDC.balanceOf(sandwicher), 1_000_000e6, "Sandwicher should profit"); } // Draft your report while the finding is fresh in your mind // Title + Severity + 3-sentence impact + PoC test + mitigation

Day 7: Finalize and Submit

⚠️ Common Submission Mistakes

Submitting known issues: Read the contest README for "known issues" — submitting these wastes your time and may penalize you on Sherlock.

Wrong severity: A DoS that requires admin action is not Critical. A theoretical issue requiring 12 simultaneous conditions is not High. Overclaiming severity is a common beginner mistake that damages credibility with judges.

No PoC: On Code4rena and Sherlock, a Medium/High finding without a PoC is often downgraded or invalidated. Always include a working test.

Gas-only findings when time is short: If you are running out of time, skip gas optimization findings. Submit everything ≥ Low severity first.

How to Ask Clarifying Questions

🔍 Good vs Bad Questions in Audit Channels
// ❌ BAD: Reveals your finding // "Is it intentional that an attacker can drain the vault via reentrancy?" // → Now every auditor in the channel knows there's a reentrancy bug // ❌ BAD: Shows you haven't read the docs // "What does the withdraw() function do?" // → Read the README first // ✅ GOOD: Asks about behavior without revealing vulnerability // "Is it expected behavior that deposit() accepts fee-on-transfer tokens?" // "What is the intended behavior of rebalance() if the oracle reverts?" // "Is the admin key in a hardware wallet / what's the multisig threshold?" // "Is this contract expected to receive ETH via selfdestruct?" // Rule of thumb: ask about INTENT and SCOPE, not about vulnerabilities // "What happens if X" is usually safe // "Did you know X is exploitable" is always wrong in a public channel

After the Contest: Building on Your First Result

ResultWhat It MeansWhat to Do Next
0 valid findingsNormal for first audit; your scope of knowledge doesn't yet match the codebase typeStudy the winning reports; identify which patterns you missed; read one lesson per day
1-3 Low/InformationalGood start — you understand code quality issues and Solidity patternsFocus next audit on finding Medium-level issues; study oracle and token handling
1-2 Medium findingsExcellent for a first audit — you have a solid foundationStart aiming for Highs; study the DeFi protocol type you like most in depth
1 High findingOutstanding first result — top 5-10% for beginnersWrite a public post-mortem; keep that momentum; try a more complex contest next
💡 The Most Valuable Post-Contest Action

After every contest, read the published winning reports carefully. For every finding you missed: (1) Understand exactly what the vulnerability was. (2) Ask yourself: "At what point in my review did I see the relevant code? Why did I not flag it?" (3) Add this pattern to your personal checklist. This retrospective habit is what separates auditors who improve quickly from those who repeat the same mistakes.

Handling Scope: What Is and Is Not Fair Game

🔍 Understanding Contest Scope Documents
// Scope document example (from a typical Code4rena contest): // In scope: // - src/Vault.sol // - src/Strategy.sol // - src/Oracle.sol // Out of scope: // - lib/openzeppelin-contracts/ (standard libraries) // - test/ (test files) // - scripts/ (deployment scripts) // Gray areas (always check contest README for clarification): // - Bugs in out-of-scope files that affect in-scope contracts? // - Centralization risks (admin can rug)? // - Gas optimizations? // - Oracle manipulation if Chainlink goes down? // General rules for scope ambiguity: // 1. If the vulnerability only exists in out-of-scope code → don't submit // 2. If out-of-scope code AFFECTS in-scope code behavior → may be valid // But note clearly: "This issue is in [out-of-scope file] but affects [in-scope file]" // 3. If unsure → submit and let the judge decide // Submitting an invalid-but-honest finding rarely penalizes you // 4. "Known issues" listed in README → NEVER submit these // On Sherlock, submitting known issues reduces your accuracy rate

Building Momentum After Your First Contest

🔍 30-Day Plan After First Contest
// Week 1 (immediately after contest ends): // - Write a post-mortem for yourself: what did I find? what did I miss? // - Read all published High/Critical findings you did not find // - For each missed finding: trace through the code yourself // - Add missed patterns to your personal checklist // Week 2: // - Write a public writeup of your best finding (even if it was Low) // - Post the writeup on your platform (GitHub Pages, Hashnode, etc.) // - Tweet the writeup with relevant hashtags: #smartcontractsecurity #web3security // Week 3: // - Start your next audit contest // - Apply lessons from Week 1 explicitly // - Test: does your updated checklist catch what you missed last time? // Week 4: // - Complete the next contest // - Community engagement: respond to 3 Twitter posts from security researchers // - Join one discussion thread in Code4rena or Secureum Discord // After 3 months of this cycle: // - 3+ public writeups on your profile // - 6+ contests completed // - Personalized checklist with 20+ items // - Clear pattern: which vulnerability categories you find well, which to study more

First Payout: Practical Details

📖 How Contest Payments Work

Code4rena and Sherlock pay in USDC, typically 2-6 weeks after the contest ends (judging takes time). You need to provide a wallet address during registration. Tax treatment varies by jurisdiction — in most countries, contest winnings are taxable income at your marginal rate. Keep records of all payments received. There are no minimum withdrawal thresholds, but gas costs for small amounts may make claiming impractical on Ethereum mainnet — check if the platform supports Polygon or Arbitrum for lower fees.

Reading Protocol Tests as a Security Signal

🔍 Extracting Security Insights from Test Suites
// Tests reveal the DEVELOPER'S mental model of the protocol // Things tested = things the developer thought about // Things NOT tested = blind spots and potential vulnerabilities // Example: Vault contract test suite // What IS tested: // testDeposit() — happy path // testWithdraw() — happy path // testYieldAccrual() — basic yield calculation // What is NOT tested (and likely not considered by developer): // - deposit() with a fee-on-transfer token // - withdraw() with a blacklisted USDC recipient // - deposit() and immediate withdraw() in the same block // - withdraw() when the vault is at maximum utilization // - What happens if the oracle reverts during withdraw() // Each of these is a potential finding // How to systematically find test gaps: // 1. Run: forge coverage --report lcov // 2. Open lcov report in browser: genhtml lcov.info -o coverage/ // 3. Find all RED lines (uncovered code) // 4. Each red line in a security-critical function = priority investigation // Grep for untested require() statements: $ grep -n "require(" src/Vault.sol | wc -l # Total require count: 23 $ grep -n "expectRevert" test/Vault.t.sol | wc -l # Tested reverts: 8 // 15 untested require() paths → 15 leads to investigate

Disputing Judge Decisions After Contest

💡 When and How to Dispute

After contest results are published, you can often dispute judge decisions within a defined window (usually 24-72 hours). Dispute only when: (1) you have a clear technical argument that the judge made an error, (2) you have evidence the judge misunderstood your finding, or (3) a duplicate grouping is incorrect. Do NOT dispute because you disagree with severity (this almost never succeeds). Write a short, professional dispute explaining the technical error clearly. Aggressive or personal disputes are always counterproductive — judges remember repeat offenders.

🔍 Good vs Bad Dispute
// ❌ BAD DISPUTE: Emotional, vague, unhelpful // "This is clearly a Critical finding and should not be marked as a duplicate. // The judge made a mistake. My finding is different and should be rewarded fully." // ✅ GOOD DISPUTE: Technical, specific, respectful // "I believe my finding #47 (missing slippage in rebalance()) was incorrectly // grouped as a duplicate of finding #23 (missing slippage in harvest()). // The root causes are different: // - Finding #23: protocol calls swap() without amountOutMin (line 456) // - Finding #47: protocol passes 0 to existing amountOutMin parameter (line 891) // The fix for each is different: #23 needs a new parameter, #47 needs to use // the expected output from an oracle instead of hardcoded 0. // These are two separate issues with two separate fixes." // What makes a dispute succeed: // - Clear technical distinction (not just "they're different, trust me") // - Reference specific line numbers // - Explain what the correct fix would be for EACH finding separately // - Short (3-5 sentences) — judges read hundreds of disputes

Tracking Your Progress Over Time

MetricHow to TrackTarget After 6 MonthsTarget After 12 Months
Valid findings per contestSpreadsheet: contest name, findings count, severity3-5 Low/Med per contest1+ High per contest
Total earningsSpreadsheet: contest, payout date, USDC amount$500-$5K cumulative$5K-$30K cumulative
Findings missedAfter each contest: count published Highs you did not findMissing <80% of HighsMissing <50% of Highs
Contest participation rateTrack: audits started vs audits completed3-4 contests per month2-3 focused contests per month
Leaderboard positionMonthly screenshot of C4/Sherlock leaderboardTop 200Top 50

Scope Ambiguity and Out-of-Scope Findings

Every audit has a defined scope — specific contracts and commit hashes. Sometimes you find a critical vulnerability that is technically outside the scope but closely related. Handling this correctly protects your reputation and maximizes your payout.

🔍 Handling Scope Boundaries
// Scenario 1: Vulnerability in an out-of-scope contract // The Vault.sol (in scope) calls ExternalOracle.sol (out of scope) // ExternalOracle has a critical bug that allows price manipulation // What to do: // Submit a finding with title: "Vault.sol trusts ExternalOracle.sol which has X vulnerability" // Frame it as an IN-SCOPE issue: the in-scope vault's reliance on a vulnerable external contract // Most judges will accept this framing if you focus on the in-scope contract's failure // Scenario 2: Finding in a library used by in-scope contracts // Libraries are usually implicitly in scope if the in-scope contracts use them // Check the scope description: "all contracts in src/" usually includes libraries in src/lib/ // When in doubt: ask in Discord (ask about scope, NOT about the vulnerability) // Scenario 3: Known issues from previous audits // Many contest scope descriptions include: "The following known issues are out of scope:" // Read this list carefully BEFORE you start — don't waste time on acknowledged issues // If you find the same issue via a different attack path → submit with that distinction // Scenario 4: Governance or admin attack vectors // Sherlock specifically excludes "admin private key compromise" as a valid finding // But "admin can rug users without timelock" IS valid if admin trust is not accepted // Read platform-specific judging rules before the contest, not after

The Post-Contest Learning Protocol

💡 The Most Valuable 3 Hours After a Contest

When a contest ends and findings are published, block 3 hours for a structured post-mortem. This is the highest-leverage learning time available to an auditor. Compare every published High and Critical finding against your notes. For every finding you missed: identify (1) what pattern you did not recognize, (2) what code path you did not trace, and (3) what test you could have written to find it mechanically. Then add that pattern to your personal checklist. Over six months, this systematic practice compounds dramatically.

🔍 Post-Contest Retrospective Structure
// Post-contest retrospective template (run after every contest) // 1. FINDINGS I SUBMITTED (count each by severity) // Critical: 0 High: 1 Medium: 2 Low: 4 Info: 2 // 2. FINDINGS I MISSED (from published report) // H-1: Flash loan reentrancy in stake() // → Why I missed: Did not trace the callback path in ERC777 transfer // → Pattern to add to checklist: "ERC777 tokensReceived callback = reentrancy surface" // → Test I should have written: deploy ERC777 token, hook tokensReceived, call stake() // H-2: TWAP manipulation window = only 1 block // → Why I missed: I saw "TWAP" and assumed it was safe, did not check window length // → Pattern to add: "Always check TWAP window in seconds, not just 'is it a TWAP'" // → Test I should have written: oracle.getTWAP() on block 0 vs block 1 // 3. FINDINGS I FOUND THAT OTHERS MISSED // M-3: Missing deadline check on swaps (only 3 others found this) // → What made me find it: my checklist item "all swaps need deadline" // → Reinforce: this checklist item is high-value, keep it prominent // 4. PATTERN LIBRARY UPDATE // New patterns added this contest: 2 // Checklist items added: 2 // Total checklist items: 73 // 5. NEXT CONTEST FOCUS AREA // I consistently miss: token callback reentrancy patterns // Before next contest: read TokenSecurity lesson + Euler Finance post-mortem

Your First Payout: Practical Considerations

📖 Getting Paid in Competitive Audits

Most competitive audit platforms pay in USDC or ETH. Code4rena requires a Polygon address for payouts. Sherlock pays on Ethereum mainnet. Immunefi pays directly from the protocol to an address you provide. You will need to provide wallet information, and some platforms require KYC verification before releasing significant payouts (>$5K on some platforms). Set up a dedicated auditor wallet — never use your primary wallet for public platform profiles. Tax implications vary by jurisdiction: consult a tax professional before your first significant payout, as crypto audit income is generally treated as self-employment income.

Key Takeaways

  • Your first audit goal is learning the process, not earning money — calibrate expectations accordingly and judge success by what you learned, not what you earned.
  • Choose contests with codebases under 1000 SLOC in protocol categories you have already studied — familiarity with the domain dramatically increases finding rate.
  • The 7-day plan (Day 1: context, Day 2: automated, Days 3-4: manual, Days 5-6: PoC, Day 7: submit) gives your audit structure and prevents the common mistake of spending too much time on one area.
  • Untested require() paths in the test suite are a map of the developer's blind spots — count them and prioritize investigation accordingly.
  • Submit everything ≥ Low severity — even a Low finding demonstrates you read the code carefully and understand Solidity best practices.
  • Disputes should be short, technical, and focused on factual errors — never dispute severity disagreements alone.
  • Never ask questions in public channels that reveal your findings — ask about intent and scope, not about vulnerabilities.
  • Post-contest retrospective analysis of winning reports is the single highest-leverage learning activity between contests — schedule this time explicitly.