Reproduced Exploit
Pheasant — a zero block hash invalidates a 250 bUSD proof
optimismSendBlockInfo can be called by any user and forwards the hash into _processMessageFromRoot. That function writes blockHashs[blockNumber] = blockHash even when the hash is zero.
Chain
Optimism
Category
bridge
Date
Jun 2024
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 60332-invalidated-block-hash-in-cross-layer-communication-quantsta. Standalone Foundry PoC and full write-up: 60332-invalidated-block-hash-in-cross-layer-communication-quantsta_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/bridge/missing-validation · vuln/logic/missing-check
Reproduction: a self-contained Foundry PoC that compiles and runs offline with only
forge-std— no fork and no RPC. Trace: output.txt. PoC: test/60332-invalidated-block-hash-in-cross-layer-communication-quantsta_exp.sol.
Key info#
| Impact | HIGH — a permissionless zero hash makes a valid exit proof pay 0 of 250 bUSD |
| Protocol | Pheasant Network child checkpoint |
| Vulnerable code | _processMessageFromRoot stores blockHash with no null check |
| Bug class | A zero checkpoint invalidates proofs |
| Finding | Quantstamp (Danny Aksenov) — Pheasant Network · id 60332 |
| Report | Quantstamp Pheasant Network |
| Source | AuditVault finding |
| Status | Fixed by requiring blockHash != bytes32(0). Reproduced here as a one-chain synthetic. |
| Compiler | solc 0.8.27, cancun, via IR |
TL;DR#
optimismSendBlockInfo can be called by any user and forwards the hash into _processMessageFromRoot. That function writes blockHashs[blockNumber] = blockHash even when the hash is zero.
The child already holds 250 bUSD against block 42, and the real hash has been stored. The next call writes bytes32(0). claim of the real hash returns 0. The escrow stays at 250 bUSD.
The control rejects a zero hash. The same proof then pays 250 bUSD and the escrow ends at 0. One contract models both the permissionless send and the child store, so a second chain is not required.
The vulnerable code#
function optimismSendBlockInfo(uint256 blockNumber, bytes32 blockHash) external {
blockHashs[blockNumber] = blockHash;
// @> VULN: a zero hash was just stored; both the real hash and zero are accepted
writes += 1;
}
Preconditions#
- The child escrow holds 250 bUSD for block 42.
- A real non-zero hash was stored, and the claimer still has that hash.
- Anyone can call
optimismSendBlockInfoon this chain.
Attack walkthrough#
- Deposit 250 bUSD into the child.
- Store the real hash for block 42.
- Call
optimismSendBlockInfo(42, 0). claim(realHash)returns 0 because the stored hash is zero.- The child still holds 250 bUSD.
Control: the zero write reverts, and claim transfers 250 bUSD to the claimer.
Diagrams#
Impact#
The claimer who should receive 250 bUSD receives nothing. Those tokens stay in the child checkpoint. The control pays the same 250 bUSD.
Remediation#
Require blockHash != bytes32(0) before writing blockHashs[blockNumber], on both the Optimism and Polygon child checkpoint paths.
Sources#
Taxonomy#
severity/highvuln/bridge/missing-validation·vuln/logic/missing-check
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 60332-invalidated-block-hash-in-cross-layer-communication-quantsta_exp (evm-hack-registry mirror).
- AuditVault finding: 60332-invalidated-block-hash-in-cross-layer-communication-quantsta.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.