The RPC Bottleneck in EVM Security Learning
Learn EVM Attacks now runs every exploit reproduction fully offline — no RPC keys, no archive node, no network dependency. We added an RPC caching layer and a lightweight mock proxy that lets all 40+ Foundry fork tests replay on-chain state from committed cache data, so you can study DeFi exploits without configuring a single endpoint.
Start Learning Today
Learn EVM Attacks is an open-source Foundry-based exploit library covering reentrancy, access control, business logic flaws, oracle manipulation, bridge vulnerabilities, and more. Each case includes a structured writeup, runnable Solidity tests, and links to the original incidents. The offline caching layer means you can now run every reproduction locally or in GitHub Codespaces without any external dependencies.
The repository is actively maintained with new exploit reproductions added regularly. Start learning today!
The Problem: RPC Dependencies in Blockchain Security Testing
Every exploit reproduction in the repository uses Foundry’s createSelectFork to replay on-chain state from a specific block. That requires an archive RPC node at test time — typically a paid Alchemy or Infura plan. Tests would break when providers rate-limited requests, deprecated endpoints, or when free-tier quotas ran out. For a learning resource meant to lower the barrier to smart contract security education, requiring RPC access was a significant friction point.
How Offline EVM Fork Testing Works
The caching system has three components:
1. Cache warming (cache_warm.sh)
A one-time build step runs each attack against a real RPC via a local Anvil fork. This populates a unified rpc_cache/ directory containing Foundry’s internal RPC cache (bind to localhost:8546) and per-chain block metadata (eth_chainId, eth_gasPrice, net_version). The directory gets committed to the repository.
bash scripts/cache_warm.sh "$ETH_RPC_URL" 14684300 Exploit_FeiProtocol
2. Mock RPC proxy (mock_rpc_proxy.js)
A minimal Node.js HTTP server that stands in for a real Ethereum RPC endpoint.
It serves cached block metadata and chain-specific responses from rpc_cache/blocks/, while Foundry’s own cache handles the heavy lifting — all eth_call, eth_getStorageAt, and storage-proof requests are resolved from the local cache without any network call.
3. Devcontainer integration
Each exploit has a GitHub Codespaces devcontainer configuration. When a user opens an attack in a Codespace, attach-run.sh extracts the fork block number from the Solidity test file, starts the mock proxy, determines the correct EVM version (Berlin through Prague), and runs the exploit end-to-end. Zero setup required.
What This Means for DeFi Security Learners
- No RPC keys needed. Clone, install Foundry, run. Every attack across Ethereum, BSC, Polygon, Arbitrum, Fantom, and Gnosis Chain works out of the box.
- Deterministic smart contract exploit replays. Cached state is committed and versioned. No more flaky tests from provider outages or changed archive data availability.
- One-click GitHub Codespaces. Open any exploit in a browser-based development environment and have it execute immediately — the proxy starts automatically via the devcontainer lifecycle hooks.
- Multi-chain support. The warming scripts and proxy handle multiple EVM-compatible networks. Each chain’s metadata is stored per-block, so a BSC attack and an Ethereum attack coexist cleanly.
Adding New Exploit Reproductions With Cache Support
When contributing a new DeFi hack reproduction, the workflow is straightforward:
- Write the Foundry test with
createSelectForkpointing at the target block. - Run
cache_warm.shwith a live RPC URL, the block number, and the test contract name. - Commit the generated
rpc_cache/entries. - Verify offline execution with
test_all_cached.sh, which wipes Foundry’s local cache, restores from the committed data, and runs every attack through the mock proxy.
warm_all.sh automates cache generation across the full repository for bulk rebuilds.