Exploit Reproduction & Analysis
Exploit Taxonomy
Category 1: Reentrancy
| Exploit | Year | Loss | Root Cause |
|---|---|---|---|
| The DAO | 2016 | $60M | splitDAO called external before state update |
| Fei/Rari Fuse | 2022 | $80M | Cross-contract reentrancy via CEther |
| Curve/Vyper | 2023 | $70M | Vyper compiler bug — reentrancy lock didn't work |
| Cream Finance | 2021 | $130M | Read-only reentrancy via token callback |
Pattern: External call before state update. Attacker's fallback/receive re-enters.
Fix: CEI pattern, ReentrancyGuard, transient storage locks (EIP-1153).
Detection: Slither reentrancy-eth, manual trace of all external calls.
Category 2: Flash Loan + Oracle Manipulation
| Exploit | Year | Loss | Root Cause |
|---|---|---|---|
| bZx | 2020 | $8M | Flash loan manipulated Uniswap V2 spot price used as oracle |
| Harvest Finance | 2020 | $34M | Flash loan manipulated Curve pool price |
| Mango Markets | 2022 | $114M | Massive position to manipulate oracle price, then self-liquidated |
| Euler Finance | 2023 | $197M | Donation attack exploiting eToken/dToken accounting + flash loan |
Pattern: Borrow large amount → manipulate price in one block → profit from manipulated price → repay. Fix: TWAP oracles, Chainlink (multi-source), multi-block validation, circuit breakers. Detection: Check if any pricing function uses spot price from a single DEX.
Category 3: Bridge Exploits
| Exploit | Year | Loss | Root Cause |
|---|---|---|---|
| Ronin | 2022 | $625M | 5-of-9 validator keys compromised |
| Wormhole | 2022 | $326M | Signature verification bypass (Solana side) |
| Nomad | 2022 | $190M | Trusted root set to 0x0 — anyone could prove anything |
| Harmony | 2022 | $100M | 2-of-5 multisig compromised |
| Multichain | 2023 | $126M | Centralized control, single point of failure |
Pattern: Trust assumption failure in the off-chain component. Fix: Minimize trust, use native rollup bridges, require high validator thresholds, monitoring + circuit breakers.
Category 4: Access Control / Logic
| Exploit | Year | Loss | Root Cause |
|---|---|---|---|
| Parity Multisig | 2017 | $30M | Anyone could call initWallet() — no protection |
| Parity Freeze | 2017 | $280M locked | Library self-destructed, all wallets bricked |
| Audius | 2022 | $6M | Uninitialized proxy — attacker called initialize() |
| Compound Gov | 2021 | $80M | Bad governance proposal distributed excess COMP |
| Wintermute | 2022 | $160M | Vanity address generator (Profanity) had weak entropy |
Pattern: Missing access control, unprotected initializers, key management failure. Fix: OZ AccessControl, initializer modifier, _disableInitializers(), hardware wallets, no vanity addresses.
Category 5: Precision / Math
| Exploit | Year | Loss | Root Cause |
|---|---|---|---|
| First depositor attacks | Ongoing | Varies | ERC-4626 inflation — first deposit + donation rounds shares to 0 |
| Balancer | 2020 | $500K | Deflationary token + flash loan price manipulation |
Pattern: Integer division truncation, rounding in attacker's favor, compounding precision errors. Fix: Virtual shares (OZ 4.9+), multiply before divide, round in protocol's favor, use WAD math.
Foundry Fork Test Reproduction Template
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test, console2} from "forge-std/Test.sol";
import {IERC20} from "forge-std/interfaces/IERC20.sol";
contract ExploitReproduction is Test {
// Fork at the block BEFORE the exploit
uint256 constant FORK_BLOCK = 15_000_000;
string constant RPC = "https://eth-mainnet.g.alchemy.com/v2/KEY";
// Addresses involved
address constant VICTIM_CONTRACT = 0x1234...;
address constant ATTACKER = 0xAttacker...;
address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
function setUp() public {
vm.createSelectFork(RPC, FORK_BLOCK);
}
function test_exploit() public {
// 1. Set up attacker
vm.startPrank(ATTACKER);
vm.deal(ATTACKER, 100 ether);
// 2. Log state before
uint256 victimBalBefore = IERC20(USDC).balanceOf(VICTIM_CONTRACT);
console2.log("Victim balance before:", victimBalBefore);
// 3. Execute exploit steps
// Step 1: Flash loan
// Step 2: Manipulate price
// Step 3: Exploit vulnerability
// Step 4: Repay flash loan
// 4. Log state after
uint256 victimBalAfter = IERC20(USDC).balanceOf(VICTIM_CONTRACT);
uint256 attackerProfit = IERC20(USDC).balanceOf(ATTACKER);
console2.log("Victim balance after:", victimBalAfter);
console2.log("Attacker profit:", attackerProfit);
// 5. Assert the exploit worked
assertGt(attackerProfit, 0, "Exploit should be profitable");
assertLt(victimBalAfter, victimBalBefore, "Victim should lose funds");
vm.stopPrank();
}
}
Exploit Pattern Library (Audit Checklist)
| Pattern | Detection Method | Prevention |
|---|---|---|
| Reentrancy | Trace external calls before state updates | CEI, ReentrancyGuard, transient storage |
| Read-only reentrancy | Check if view functions read stale state during callback | Lock state reads too, not just writes |
| Flash loan price manipulation | Spot price used for critical decisions? | TWAP, Chainlink, multi-block |
| First depositor inflation | ERC-4626 first mint path? | Virtual shares, dead shares |
| Unprotected initializer | Proxy impl without _disableInitializers()? | Always disable + initialize atomically |
| Storage collision (proxy) | Storage layout changed between versions? | Append-only, OZ upgrades-core validation |
| Signature replay | Nonce + chainId + contract address in domain? | EIP-712 domain separator |
| Unchecked return value | Low-level call without success check? | SafeERC20, always check returns |
| tx.origin auth | Any tx.origin usage? | Replace with msg.sender |
| Forced ETH | Logic depends on address(this).balance? | Internal accounting, not balance |
| Precision loss | Division before multiplication? | Multiply first, WAD math, round in protocol's favor |
| Unbounded loop | Array iteration with external-controlled length? | Pagination, bounded gas, pull pattern |
| Oracle staleness | Freshness check on price feed? | require(updatedAt > block.timestamp - maxAge) |
| Governance flash loan | Snapshot at proposal time? | getPastVotes at proposal creation block |
| Centralization | Single EOA owns admin keys? | Multisig + timelock |
DeFiHackLabs Study Guide
Located at: /data/.openclaw/workspace-chain/repos/DeFiHackLabs/
Study order (most educational exploits first):
- Euler Finance (flash loan + donation attack)
- Curve/Vyper reentrancy (compiler bug)
- Nomad Bridge (initialization bug)
- Mango Markets (oracle manipulation)
- Cream Finance (read-only reentrancy)
- Harvest Finance (flash loan + Curve manipulation)
- bZx (first flash loan attack)
- Compound governance (bad proposal)
- Audius (uninitialized proxy)
- Parity Multisig (access control)
- First depositor attacks (ERC-4626)
- Balancer (deflationary token + flash loan)
- Wintermute (vanity address weakness)
- Wormhole (signature verification bypass)
- Ronin Bridge (key management failure)
For each: read the code, understand the bug, run the reproduction, write the fix.