name: reentrancy description: Hunt and validate reentrancy bugs — classic cross-function, same-function, read-only, and cross-contract variants. metadata: subdomain: smart-contracts when_to_use: "reentrancy cross-function read-only erc777 erc1155 hook callback evm" mitre_attack: - T1190
Reentrancy Playbook
Variants
- Classic — external call before state update (The DAO)
- Cross-function — A calls out, reentered into B which reads/writes A's state
- Read-only — view function reads stale state during reentrancy, consumed by a second contract making decisions
- Cross-contract — same attack pattern across protocol boundaries
- ERC777 / ERC1155 hook —
onERC*Receivedcallback re-enters
Audit steps
solidity_scan_fileflags every.call{value:...}anddelegatecall- For each hit, check:
- Is there a state write BEFORE the external call?
- Is
ReentrancyGuard'snonReentrantmodifier applied? - Does it follow checks-effects-interactions?
- Trace call graph — if any function the call target can invoke reads or writes the same state slot, that's a reentrancy chain.
PoC via Foundry
foundry_reentrancy_test(target="Vault", function="withdraw", target_path="src/Vault.sol")
Then:
cp generated.t.sol /workspace/foundry/test/
cd /workspace/foundry && forge test -vvv --match-contract Test_withdraw
Success criteria
The attacker contract balance grows by more than its initial deposit after the attack transaction. The Foundry test should assert this.
CVSS
- Direct fund drain:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H= 10.0 - Read-only with downstream impact: 8.1-9.1 depending on impact
Known exemplars
- The DAO (2016)
- Lendf.Me (2020, ERC777 hook reentrancy, $25M)
- Cream Finance (2021)
- Rari Capital (2022)
- Curve pool read-only reentrancy (2023)