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.

Aug 2024•Other•bridge•3 min read

Chain

Other

Category

bridge

Date

Aug 2024

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

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.

Loading fork state…

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-registry mirror.


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#

ImpactHIGH — a failed batch reply leaves 1000 escrowed tokens on L1
ProtocolBoba L1ERC1155Bridge.finalizeWithdrawalBatch
Vulnerable codereplyNeeded encodes finalizeDeposit.selector instead of finalizeDepositBatch.selector
Bug classThe refund message cannot be decoded
FindingQuantstamp (Pavel Shabarkin) — Boba bridges · id 60699
ReportQuantstamp Boba
SourceAuditVault finding
StatusFixed in commit 535c64c9 by using the batch selector. Reproduced here as a local synthetic.
Compilersolc 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#

SOLIDITY
// @> 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.
  • replyNeeded is true, so the bridge must send a completing message.
  • The tokens are pulled before that message is attempted.

Attack walkthrough#

  1. Mint 1000 and approve the L1 bridge.
  2. Call finalizeWithdrawalBatch with ids [1, 2], amounts [400, 600], and replyNeeded = true.
  3. The bridge escrows 1000.
  4. The message uses finalizeDeposit.selector.
  5. L2 reverts on payload length. The refund never runs.
  6. The bridge balance is 1000 and the user balance is 0.

Control: the same call with finalizeDepositBatch.selector returns 1000 to the user.

Diagrams#

flowchart TD A["Batch is ids 1 and 2 for 400 and 600"] --> B["L1 pulls 1000 into escrow"] B --> C["replyNeeded encodes finalizeDeposit"] C --> D["L2 rejects the batch-shaped payload"] D --> E["refund is never called"] E --> F["User balance is 0 and L1 still holds 1000"]

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/high
  • vuln/bridge/missing-validation · vuln/logic/wrong-condition

Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

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.