Your First Real Target: Public-Scope Workflow (Fork-Only Testing)
A web3 bug bounty workflow is not “open Etherscan and spray AI reports.” It is: pick an authorized public program, read scope like a contract, clone what is in scope, triage with Slither, review by hand, and prove hypotheses only on a local Foundry/Anvil fork. This Andrax tutorial — by Syed Zada Abrar — covers ~30% theory and ~70% practical workflow for your first authorized public-scope hunt.
Prerequisites (live): How to Write an Immunefi Bug Report; Submit Immunefi / CodeHawks / Sherlock 2026; Foundry + Slither Setup; Hub. Also useful: How to Start Web3 Bug Hunting; Read Verified / Unverified Contracts; Access Control Bugs; Reentrancy.
Ethics fence (non-negotiable): Immunefi rules ban any testing with mainnet or public testnet contracts for programs on the platform — immediate permanent ban risk. Your PoC runs on a local network or local mainnet fork (Anvil / forge test --fork-url), never as a broadcast transaction against live in-scope code. Do not probe, scan, or “confirm” exploits on live deployments. Do not invent a finding and submit spam. This lab stops at fork-only hypothesis tests you keep offline until you have a complete, honest report (Spokes 14–15).
Primary references: Immunefi rules; Immunefi paid-report guide; IVS v2.3; Foundry fork testing; Anvil reference; vm.createSelectFork; Slither usage.
Theory in one page — why “public scope” still has hard walls
| Idea | Hunter meaning |
|---|---|
| Public program | Written rules on a bounty page anyone can open (Immunefi explore) |
| In scope | Assets + impact classes the project will pay for |
| Out of scope (OOS) | Listed exclusions + Immunefi defaults (best-practice nits, already public bugs, etc.) |
| Authorized test surface | Local clone, local deploy, local fork of chain state — not the live mempool |
| PoC | Runnable Foundry/Hardhat test that demonstrates impact on that local/fork surface |
Immunefi’s own report guide requires PoCs tested on a local network / mainnet fork, not mainnet or public testnet (paid-report guide). Fork ≠ permission to attack production. A fork is a local copy of state for simulation (Foundry fork testing).
Step 0 — Pick a low-competition public program (selection checklist)
Do not chase the highest TVL logo on day one. Prefer a program you can finish reading in one sitting.
Immunefi program scope checklist (fill this before you clone):
| Field | Your notes (private) |
|---|---|
| Program name + URL | |
| Assets in scope (repos / addresses / chains) | |
| Impacts in scope (map to IVS language) | |
| Explicit OOS | |
| PoC required? Runnable? | |
| Primacy of Impact / known issues / prior audits | |
| KYC / payout geography notes | |
| “Low competition” signals you used (newer listing, smaller surface, clear repo — your judgment, not a scraped rank) | |
| STOP line: what would be mainnet testing? | Broadcasting any exploit tx / public-testnet probe of listed assets |
Selection heuristics (not guarantees):
- Clear GitHub (or equivalent) for in-scope contracts — you can
git clonewithout guessing. - Readable impact table — you know what Critical means for this program.
- Manageable surface — fewer modules, fewer chains, fewer “all peripheral scripts” surprises.
- You already understand the class — vault / access control / oracle path you studied in earlier spokes.
- You will not touch anything marked OOS — including websites, socials, and “informational” nits dressed as High.
Open immunefi.com/explore, pick one educational target, and fill the table. This tutorial never names a live payout target to “attack” — your notes name your chosen public program.
Step 1 — Freeze scope, then clone
- Screenshot or copy the program’s assets / impacts / OOS into your notes (date-stamp IST).
- Clone only repositories listed as in-scope (or the exact monorepo path the program points to).
- Record commit SHA:
git rev-parse HEAD. - Create a working branch for notes only — do not open PRs “fixing” the project without consent (Immunefi rules prohibit submitting fixes to a project’s repository without express consent).
# ILLUSTRATIVE — replace with YOUR in-scope repo URL from the program page
mkdir -p ~/labs/bounty-targets && cd ~/labs/bounty-targets
git clone <IN_SCOPE_REPO_URL> day17-target
cd day17-target
git rev-parse HEAD
If the program lists deployed addresses but no repo, use verified source via explorer / Sourcify literacy from read contracts — still no live probing.
Step 2 — forge build (or import into Foundry)
Prefer a Foundry-native tree. If the repo is Hardhat/Truffle-first, either:
- follow the project’s documented install, or
- create a thin Foundry wrapper that points
src/ remappings at the contracts you will review (Spoke 05 patterns).
# After deps / remappings are correct for YOUR clone
forge build
forge remappings | tee ~/labs/notes/day17-remappings.txt
Gate: if it does not compile, fix remappings / solc version before trusting Slither. Half-built trees produce noise, not leads.
Step 3 — Slither triage (candidates, not verdicts)
# From Spoke 05 — venv + built artifacts
slither . --filter-paths "lib|node_modules" | tee ~/labs/notes/day17-slither.txt
# Optional second opinion later: aderyn .
Fill a smart contract manual review checklist triage table (copy into notes):
| # | Detector / note | File:line | In my scope code? | Plausible impact (IVS)? | Next |
|---|---|---|---|---|---|
| 1 | Y/N | Discard / read / forge hypothesis | |||
| 2 |
Rules of triage:
- Dependency findings under
lib/→ filter or demote unless the program’s asset is that library copy. - Naming / style detectors → discard for bounty (OOS best-practice).
- Reentrancy / arbitrary-send / unprotected-upgrade hints → read the code, then decide if a fork PoC is warranted.
- Tool severity ≠ Immunefi severity. Impact you can demonstrate wins (IVS).
Step 4 — Manual review pass (70% of the hour)
Walk entrypoints the program actually exposes. Use this manual review checklist:
| Check | Questions |
|---|---|
| Access control | Who can call privileged setters / upgrades / sweeps? Missing onlyOwner / role? (access control) |
| CEI / reentrancy | External call before state update? ERC-777/1155 hooks? (reentrancy) |
| Accounting | Share math, rounding, donation / inflation paths (ERC-4626 spoke if vaults) |
| Oracle / price | Spot vs TWAP; who can update; flash-loan same-block |
| Upgrade / proxy | authorizeUpgrade, storage layout, init |
| Signatures | Domain separator, nonce, chainid binding |
| Economic assumptions | Flash liquidity for votes / collateral; sequencer downtime (often OOS on some pages) |
| OOS filter | Would this be “best practice,” centralization risk, or already public? |
Write hypotheses as one line each: “If X is true, an unprivileged caller can Y, causing Z impact listed on the program page.”
No hypothesis → no fork test. Curiosity without impact is not a report.
Step 5 — Foundry mainnet-fork PoC (local only)
Goal: prove or kill a hypothesis against forked state on your machine. You are not sending exploit transactions to Ethereum mainnet or a public testnet of the target.
5a — Anvil fork (interactive local node)
From the Anvil reference: --fork-url forks live network state into a local Anvil node. Experiments talk to 127.0.0.1, not the public mempool.
# Read-only RPC for state fetch — experiments stay on Anvil
export ETH_RPC_URL="https://YOUR_PUBLIC_OR_KEYED_RPC" # gitignore secrets
anvil --fork-url "$ETH_RPC_URL" --fork-block-number <PINNED_BLOCK>
# RPC: 127.0.0.1:8545 — Anvil printed keys are LOCAL ONLY
Pin --fork-block-number for reproducibility (fork testing guide).
5b — forge test --fork-url (preferred for PoC files)
forge test --match-test test_HypothesisName \
--fork-url "$ETH_RPC_URL" \
--fork-block-number <PINNED_BLOCK> -vvv
Or use cheatcodes inside the test (vm.createSelectFork / createFork + selectFork in the same guide family).
5c — ILLUSTRATIVE hypothesis skeleton (pattern only)
This is a shape, not an exploit against a named live program. Replace addresses/interfaces with your in-scope targets from notes. Assert a state fact that supports or kills the hypothesis. If you cannot demonstrate in-scope impact, delete the lead.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
/// @notice ILLUSTRATIVE / LOCAL FORK LAB ONLY.
/// @dev Replace TARGET with an address from YOUR program's in-scope list.
/// Do not broadcast exploit txs to mainnet or public testnets.
interface IMinimalView {
function owner() external view returns (address);
}
contract Day17ForkHypothesisTest is Test {
// Placeholder — paste from YOUR scope notes, not from this tutorial
address constant TARGET = address(0xDeaD); // replace
function setUp() public {
// Alternative to CLI --fork-url: vm.createSelectFork(vm.envString("ETH_RPC_URL"), BLOCK);
// Prefer CLI pin for first labs — see getfoundry.sh fork-testing guide
}
function test_hypothesis_unprivilegedCannotBreakInvariant() public {
vm.skip(TARGET == address(0xDeaD)); // force you to replace before treating as real
address attacker = makeAddr("attacker");
IMinimalView t = IMinimalView(TARGET);
// Example *read* on forked state — not an attack
address own = t.owner();
assertTrue(own != address(0), "owner readable on fork");
// Example: attempt a privileged path as attacker *in simulation*
// vm.prank(attacker);
// IPrivileged(TARGET).onlyOwnerThing(...);
// vm.expectRevert();
// ...
// If your real hypothesis shows funds-at-risk, assert balances / shares here.
// STOP: do not cast send / broadcast the same calldata to a live RPC.
}
}
Hard STOP before:
- Any
cast send/ wallet tx against the live in-scope deployment - Public testnet “confirmation” of the same bug
- Out-of-scope assets (frontends, third-party vaults, unmarked chains)
- Submitting a half-finished or AI-spray report (rules · paid-report guide)
If the fork PoC proves impact: write the report in Spoke 14 section order, then submit via Spoke 15’s platform checklist — still without live testing.
Lab — 45-minute fork-only run (do this today)
Timebox:
| Min | Action |
|---|---|
| 0–10 | Pick one public program; fill Immunefi program scope checklist |
| 10–15 | Clone; record SHA; forge build (or document why build failed) |
| 15–25 | slither . triage table (max 10 rows you will actually read) |
| 25–35 | Manual checklist on two entrypoints; write ≤3 hypotheses |
| 35–45 | One fork test that reads or simulates a hypothesis; log PASS/FAIL of hypothesis |
| End | Confirm: zero mainnet/public-testnet interactions with in-scope code |
ILLUSTRATIVE lab log (keep offline):
Date (IST):
Program URL:
Commit SHA:
forge build: OK / FAIL (note)
Slither rows kept for reading:
Hypotheses (≤3):
Fork block pinned:
forge test result (hypothesis held? Y/N):
Mainnet / public-testnet txs sent to in-scope code? NO (required)
Submitted a report today? NO unless complete + honest + local PoC
Common traps
| Trap | Better habit |
|---|---|
Forking, then cast send to mainnet “to prove it” | Ban territory — keep simulation local (rules) |
| Filing every Slither High | Manual + fork proof or discard |
| Skipping the program OOS list | Scope table first |
| Targeting mega-TVL week one | Smaller clear surface |
| Submitting without runnable PoC | Spoke 14 template |
| Fix PR to the project repo unsolicited | Consent required (rules) |
| Soft-testing on “public testnet of the same code” | Still prohibited on Immunefi |
Workflow map (print this)
Explore public programs
↓
Scope checklist (assets / impacts / OOS / PoC / KYC)
↓
Clone @ SHA → forge build
↓
Slither triage table
↓
Manual review checklist → hypotheses
↓
Anvil / forge test --fork-url (LOCAL ONLY)
↓
impact proven? ──no──→ discard / next hypothesis
↓ yes
Report (Spoke 14) → Submit lane (Spoke 15)
↓
NEVER: live in-scope mainnet / public-testnet testing
Next steps
- Prev (live): Submit Immunefi / CodeHawks / Sherlock 2026 · Write Immunefi Bug Report
- Toolchain: Foundry + Slither
- Hub: Web3 Bug Hunting Learning Path 2026
- Start: How to Start Web3 Bug Hunting
Work only on authorized bounty programs, local forks, and CTF/lab environments — never against mainnet or public-testnet deployments of in-scope code. Build competence before you submit.
Educational content by Syed Zada Abrar for Andrax (andraxpentester.in). Authorized research only. Lab is fork-only / local — no mainnet or public-testnet testing of in-scope code; no live scanning or probing.