EVM Contract Fuzzing Framework
Sigvex coverage-guided EVM fuzzing framework with ABI-aware input generation, property-based invariant checking, symbolic execution, multi-contract execution, and transaction sequence fuzzing.
EVM Contract Fuzzing Framework
Overview
The EVM fuzzing framework is a coverage-guided fuzzing engine for Ethereum smart contracts. It combines ABI-aware input generation with a library of over 60 DeFi function signatures, property-based invariant checking, symbolic execution for path exploration, multi-contract execution with flash loan simulation, and transaction sequence fuzzing with state persistence.
The framework validates vulnerabilities that static detectors cannot confirm: successful exploits that cause state changes without reverting. A reentrancy attack drains funds successfully. An integer overflow mints tokens silently. The invariant system detects these outcomes by analyzing post-execution state changes rather than looking for crashes or panics.
Note: The fuzzing framework is for vulnerability validation purposes only. Findings produced by fuzzing represent confirmed or likely-exploitable vulnerabilities in the analyzed contract.
Invariant Checkers
The framework includes six property-based invariant checkers that run after every successful execution:
| Checker | Violation Detected | Severity |
|---|---|---|
| Reentrancy | Re-entrant calls that exploit intermediate state before storage updates complete | Critical |
| Balance Conservation | Unauthorized decreases in ETH or token balances across a transaction | Critical |
| Access Control | Privileged functions executing from unauthorized caller addresses | High |
| Integer Overflow | Arithmetic operations producing wrapped or out-of-range results in storage | High |
| Selfdestruct | Contract destruction triggered by an unauthorized caller | Critical |
| Taint Violation | User-controlled values reaching storage slots or authentication checks | High |
Each invariant is evaluated against a snapshot of contract state before and after execution, including the full execution trace with external calls, storage reads and writes, and balance changes. A violation is generated only when the post-execution state diverges from the expected invariant in a way that indicates exploitability.
Attack Scenario
The fuzzer discovers vulnerabilities by executing thousands of randomized transaction sequences and checking invariants after each successful execution. A typical fuzzing-driven exploit discovery follows this flow:
- Corpus initialization: The fuzzer seeds its corpus with valid function calls derived from the contract’s ABI and known DeFi interaction patterns.
- Coverage-guided mutation: Inputs that increase code coverage (new basic blocks reached) are retained in the corpus and mutated for further exploration.
- Invariant checking: After each successful execution (no revert), all enabled invariant checkers evaluate the pre/post state snapshot.
- Violation detected: When an invariant fails — for example, an unauthorized balance decrease — the triggering input is recorded as an exploit candidate.
- Crash reproduction: The triggering input is replayed in isolation to confirm reproducibility and generate a proof-of-concept transaction.
For multi-contract scenarios (flash loan attacks, reentrancy via callbacks), the framework simulates multiple contracts executing within the same transaction context.
Exploit Mechanics
Coverage-Guided Fuzzing
The fuzzer tracks basic block coverage across executions. Inputs that explore new code paths are prioritized for mutation. This ensures that even rare execution paths — such as the second branch of a complex conditional — are exercised.
Coverage information feeds the corpus scheduler, which assigns energy (number of mutations) to seeds based on how much new coverage they contributed. High-coverage seeds receive more mutation budget.
ABI-Aware Input Generation
The input generator produces syntactically valid calldata based on known Solidity function signatures. For unknown contracts (bytecode-only analysis), the generator extracts function selectors from the bytecode and applies heuristic parameter type inference.
// Example: Generated inputs for a lending contract
// The fuzzer generates valid deposit, borrow, repay, liquidate sequences
// and mutates amounts, addresses, and timing to find edge cases
// Discovered: borrow() can be called with zero collateral if a prior
// deposit() call from the same address is still in the pending state
function exploit(address target) external {
ILendingPool pool = ILendingPool(target);
// Fuzzer discovered: deposit 1 wei, then borrow max — collateral check bypassed
pool.deposit{value: 1}();
pool.borrow(pool.totalLiquidity()); // Succeeds: balance conservation violated
}
Symbolic Execution
In addition to concrete execution, the framework includes a symbolic execution engine that explores program paths without concrete inputs. Symbolic execution assigns symbolic variables to calldata, storage reads, and environment values (block number, timestamp), then propagates symbolic expressions through the bytecode.
When a symbolic expression can reach a sensitive operation — a storage write, an ETH transfer, or a selfdestruct — the constraint solver generates concrete inputs that trigger the path. This is particularly effective for finding vulnerabilities that require specific input values, such as integer overflow at exact boundary conditions.
Multi-Contract and Flash Loan Fuzzing
The multi-contract executor simulates DeFi-specific attack patterns that require interactions between multiple contracts in a single transaction:
- Flash loan attacks: Borrows a large amount from a lender, manipulates the victim protocol’s state at inflated values, and repays — all atomically.
- Reentrancy via callbacks: Deploys a malicious receiver contract that re-enters the victim during an ETH transfer or token callback.
- Cross-contract price manipulation: Manipulates a DEX reserve via one contract, then reads the manipulated price in a second contract.
Transaction Sequence Fuzzing
The sequence fuzzer discovers multi-transaction state attacks — vulnerabilities that require setting up specific state across multiple blocks before the exploit transaction. Examples include:
- Governance attacks that require accumulating vote tokens before a proposal
- Time-delayed attacks that exploit oracle TWAP accumulation
- Multi-step flash loan attacks with intermediate state checkpoints
Remediation
Individual vulnerability findings from the fuzzer link to their corresponding detector and remediation documentation. Common fuzzer-discovered vulnerability classes include:
- Reentrancy: Reentrancy Detector | Remediation
- Integer Overflow: Integer Overflow Detector | Remediation
- Access Control: Access Control Detector | Remediation
- Flash Loan: Flash Loan Detector | Remediation