Reproduced Exploit
Boba — the wrong ERC1155 selector keeps 1000 tokens on L1
The user bridges an ERC1155 batch: id 1 for 400 and id 2 for 600. The escrow token models that sum, N = 1000.
Chain
Other
Category
bridge
Date
Aug 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: 60699-using-the-wrong-selector-causes-token-loss-during-erc1155-br. Standalone Foundry PoC and full write-up: 60699-using-the-wrong-selector-causes-token-loss-during-erc1155-br_exp in the
evm-hack-registrymirror.
Vulnerability classes: vuln/bridge/missing-validation · vuln/logic/wrong-condition
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/60699-using-the-wrong-selector-causes-token-loss-during-erc1155-br_exp.sol.
Key info#
| Impact | HIGH — a failed batch reply leaves 1000 escrowed tokens on L1 |
| Protocol | Boba L1ERC1155Bridge.finalizeWithdrawalBatch |
| Vulnerable code | replyNeeded encodes finalizeDeposit.selector instead of finalizeDepositBatch.selector |
| Bug class | The refund message cannot be decoded |
| Finding | Quantstamp (Pavel Shabarkin) — Boba bridges · id 60699 |
| Report | Quantstamp Boba |
| Source | AuditVault finding |
| Status | Fixed in commit 535c64c9 by using the batch selector. Reproduced here as a local synthetic. |
| Compiler | solc 0.8.27, cancun, via IR |
TL;DR#
The user bridges an ERC1155 batch: id 1 for 400 and id 2 for 600. The escrow token models that sum, N = 1000.
finalizeWithdrawalBatch pulls the 1000 first. Because replyNeeded is true, it sends a message to L2. The selector on that message is finalizeDeposit, the single-id function, while the arguments are the batch arrays.
L2's finalizeDeposit requires a three-word payload. The batch encoding is longer, so the call returns false. Nothing calls refund. The user balance is 0 and the L1 bridge still holds 1000.
The control encodes finalizeDepositBatch.selector. L2 sums the amounts and refund returns 1000 to the user.
The vulnerable code#
// @> VULN: batch reply uses the single-deposit selector
bytes memory message =
abi.encodeWithSelector(IL2ERC1155Bridge.finalizeDeposit.selector, user, ids, amounts);
(bool ok,) = l2.call(message);
Preconditions#
- The withdrawal is a batch of two ids whose amounts sum to 1000.
replyNeededis true, so the bridge must send a completing message.- The tokens are pulled before that message is attempted.
Attack walkthrough#
- Mint 1000 and approve the L1 bridge.
- Call
finalizeWithdrawalBatchwith ids[1, 2], amounts[400, 600], andreplyNeeded = true. - The bridge escrows 1000.
- The message uses
finalizeDeposit.selector. - L2 reverts on payload length. The refund never runs.
- The bridge balance is 1000 and the user balance is 0.
Control: the same call with finalizeDepositBatch.selector returns 1000 to the user.
Diagrams#
Impact#
The user loses the 1000 tokens that were escrowed for the batch. A correct selector returns the same 1000.
Remediation#
Encode iL2ERC1155Bridge.finalizeDepositBatch.selector when the reply is for a batch withdrawal.
Sources#
Taxonomy#
severity/highvuln/bridge/missing-validation·vuln/logic/wrong-condition
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 60699-using-the-wrong-selector-causes-token-loss-during-erc1155-br_exp (evm-hack-registry mirror).
- AuditVault finding: 60699-using-the-wrong-selector-causes-token-loss-during-erc1155-br.
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.