A fully static, backend-free, in-browser EVM exploit debugger. Point it at any transaction hash and it will:
- Fork chain state at the block before the tx (via plain archive JSON-RPC).
- Replay the exact historical transaction in an in-browser EVM
(
@ethereumjs/vm), recording every opcode across all call depths — stack, memory, storage writes, transient storage, gas, and the full call-frame tree. - Download the verified Solidity sources of every contract the tx touched
(Etherscan V2), compile them in a Web Worker with their exact settings,
and match the on-chain bytecode to produce a
pc → source-linemap. - Let you step opcode-by-opcode or line-by-line with the Solidity source, opcodes, stack, memory, and storage kept in sync — and mark the vulnerable line plus an ordered set of exploit steps, each with a description.
- Export the whole thing as a ZIP, or pin it to IPFS (Pinata) and share a link. Anyone opening the link replays the exploit locally — no server, no RPC.
Everything runs in your browser. The only network calls are to the RPC you
provide, Etherscan, binaries.soliditylang.org (the official solc binaries, for
compilation only), IPFS gateways, and Pinata (only if you choose to upload).
It also opens curated scripted exploit ZIPs from evm-hack-poc (generated from evm-hack-registry data — the same dataset shown on crypto.training/hacks).
| Project | Role |
|---|---|
| evm-hack-registry | Source registry / structured hack data |
| evm-hack-analyzer (this repo) | Analyzer UI & tooling to inspect and annotate exploits |
| evm-hack-poc | Shareable PoC ZIP archives for the community |
| crypto.training/hacks | Public browsable mirror of this dataset |
npm install
npm run dev # http://localhost:5173
npm run build # static site → dist/
npm run previewProvide a transaction hash, an archive RPC URL (must serve historical
eth_getBalance / eth_getCode / eth_getStorageAt — e.g. Infura, Alchemy,
QuickNode), and an Etherscan V2 API key (one key works for every supported
chain — the chain id is detected from the RPC). Click Generate POC.
Heavy transactions (hundreds of touched contracts) can take a few minutes, because state is fetched lazily one slot at a time over your RPC.
- Mark vuln → click the vulnerable source line → title + description.
- Mark step → click source lines in exploit order → title + description each.
These power the Go to vulnerability and Watch exploit live buttons.
- ⬇ poc.json → single self-contained JSON (canonical; best for IPFS / re-load).
- Download ZIP → human-readable projection without duplicating bulk data:
anvil_state.json(fork state),sources/<addr>/…(Solidity files),poc-data/core.json(tx + pc→line maps + annotations only). Reassembled on load. - Upload to IPFS → enter Pinata API key + secret → get a CID and a share link
of the form
…/#<CID>. Opening that link loads and replays the POC straight from IPFS (tries your gateway, thenipfs.io, thendweb.link).
You can also publish your PoC on IPFS if you want your research to be truly decentralized.
After you analyze a hack, mark the vulnerability and the exploit execution steps, then:
- Save your PoC as a ZIP
- Open a pull request on evm-hack-poc
The most valuable and interesting PoCs will be merged so the whole community can benefit from your research. We plan to expand hack PoC coverage beyond the original DeFiHackLabs set — contributions are really welcomed and much appreciated.
The analyzer opens ZIP files from
evm-hack-poc (scripted exploit
bundles with poc-data/runner.json + anvil_state.json + sources/). Drop a
.zip onto the Load card, or open its IPFS CID.
Those archives are generated from evm-hack-registry and mirror the data on crypto.training/hacks.
Unlike a native POC (one historical tx replayed from accounts), these ZIPs
describe a scripted exploit: the analyzer loads the dumped fork state and
runs it in the same in-browser EVM — deploy (or etch) the attack contract,
apply setup (vm.deal/warp/roll/store/dealToken), then record the
attack (an attackFunction() call or a callScript) opcode-by-opcode. The
resulting recording drives the identical debugger (opcodes, call tree, memory /
stack / storage, source stepping), with the exploit contract's source and the
vulnerability + story annotations resolved onto the deployed exploit
address. No RPC or Etherscan key is needed — everything the exploit touches is
already in the bundle. Export re-emits a ZIP (or optionally re-annotated
poc-data JSON) that round-trips through the loader and IPFS.
The canonical native artifact is a single self-contained JSON (.poc.json
download / IPFS pin): transaction envelope + block, the exact fork accounts
(code + storage + balance the tx touched), verified contractSources (with
pcToLine), human labels, and the vulnerability + story annotations. The
viewer deterministically re-runs the tx from accounts, so a POC replays
identically wherever it is loaded.
The ZIP is a space-efficient, browsable projection of that same data: fork
state and source trees live as separate files; a slim poc-data/core.json holds
only what those projections omit (tx, maps, annotations). Older ZIPs that
embedded a full poc-data/poc.json still load.
Loading is format-detecting: a JSON with the evm-hack-analyzer-poc kind
marker takes the tx-replay path above; a ZIP from
evm-hack-poc (or a runner JSON with
slug + expected + accounts, no kind) takes the scripted-exploit path.
npm run build emits a fully relative-path dist/ (Vite base: "./"), so it
works from any gateway subpath. Pin the folder:
npx kubo add -r dist # or: ipfs add -r dist / Pinata "pin a folder"Open https://<gateway>/ipfs/<siteCID>/ and share POC links as
https://<gateway>/ipfs/<siteCID>/#<pocCID>. The #<pocCID> hash is read on
load — gateway-path-agnostic, so it survives any gateway prefix.
- State forking uses
eth_getBalance/getCode/getStorageAt, noteth_getProof, because public providers capeth_getProofto a recent block window. - Same-block dependencies: state is forked at
block-1, so a tx that depends on an earlier tx in the same block may diverge (standard fork-testing caveat). - Source mapping requires a verified, bytecode-matching contract; proxies and unverified contracts render as opcode-only (the vulnerability can still be anchored on any contract that does map, e.g. the token whose balance moves).
- solc runs in a Web Worker loading the official
soljson-<version>.js; this happens only during generation. Viewing a POC needs no solc and no RPC.
These materials are for educational and defensive security research only.
- Do not use this content to attack live systems or steal funds.
- Always follow applicable law and responsible disclosure practices.
- Reproducing historical exploits should be done in local / forked environments only.