Worked example · 2026-05
MAP Protocol — Butter Bridge abi.encodePacked hash-collision + retry-message replay — 2026-05-20
Summary
MAP Protocol operates Butter, a cross-chain bridge connecting MAP Relay Chain, Ethereum, BNB Chain and other networks. Cross-chain transfers are authorised by an oracle-and-multisig-signed message; the bridge supports a retry path so that a transfer whose destination-side execution failed can be re-submitted and completed.
On 2026-05-20, an attacker abused the retry path to mint one quadrillion MAPO on Ethereum with no corresponding lock or burn on the source chain. Per Blockaid's root-cause analysis, the sequence was:
- The attacker initiated a legitimate MAP→ETH bridge message, signed through the bridge's oracle and multisig validation. This message was genuine — no signature was forged and no key was compromised.
- The attacker deployed a new contract at a precomputed address (CREATE2, so the address could be known in advance and referenced by the crafted message) to interpose on the bridge's retry function.
- The attacker re-presented the transfer through the retry path with a message whose fields were re-arranged so that
keccak256(abi.encodePacked(...))of the forged layout collided with the hash of the legitimate layout the bridge had already accepted. Because the bridge's retry verification trusted that packed hash as the message's integrity tag, it processed the forged message — minting 1,000,000,000,000,000 MAPO to the attacker.
The attacker swapped a portion of the minted supply into 52.2 ETH ($110K) before the market collapsed the price. MAP Protocol paused all bridge operations, and announced a recovery/migration plan: deploy a new token contract and take a snapshot to separate authentic balances from attacker-minted tokens.
Blockaid is explicit about what the incident is: a weakness in the retry message verification process, specifically the use of keccak256(abi.encodePacked(...)) over packed dynamic fields, combined with message replay and address manipulation (the precomputed contract) to bypass the validation system. It is not a signature forgery and not a validator-key compromise — the signed message the attack rode on was genuine.
Why this is structurally significant
T10.002 (Message-Verification Bypass) groups failures where a bridge releases or mints value against a message it should have rejected. Butter Bridge adds a sub-class distinct from the three already anchored in the corpus:
- Trusted-root-initialisation sub-class (Nomad, 2022-08). A contract upgrade set the trusted root to
0x00; the verifier accepted every message. The flaw was in the initialisation of verification state. - Signature/account-validation sub-class (Wormhole, 2022-02). A deprecated signature path did not validate the guardian-account address, allowing a forged VAA. The flaw was in who the proof was checked against.
- Economic-value-binding sub-class (Verus, 2026-05). Every cryptographic check passed; no check bound the payout to source-side economic totals. The flaw was a missing conservation invariant (see
examples/2026-05-verus-ethereum-bridge-source-amount-validation.md). - Hash-encoding-ambiguity sub-class (Butter, this case). The verification hash itself is ambiguous:
abi.encodePackedover multiple dynamic fields is not injective, so a forged message can be constructed that hashes identically to a legitimate one. The flaw is in the choice of hashing primitive in the verification predicate — the tag the verifier trusts does not uniquely identify the message it tags.
The four sub-classes have different detection loci. Nomad's lives at the post-upgrade smoke-test layer; Wormhole's at the pre-deployment audit of the signature path; Verus's at the invariant-specification layer; Butter's lives at the static-analysis / code-review layer, because abi.encodePacked with ≥2 dynamic arguments feeding a security-relevant hash is mechanically detectable before deployment. This makes Butter the most preventable of the four: the anti-pattern is documented, lint-detectable, and has been the subject of public Solidity guidance for years. The teaching value is precisely that a known, tool-detectable footgun reached a production bridge's verification path.
The case also pairs the replay and collision primitives: the collision alone is inert without a legitimate signed message to collide against, and the replay alone would be caught by a nonce/used-message check. The attacker needed both — a genuine signed message (the replay carrier) and an ambiguous integrity tag (the collision) — plus a precomputed contract address to make the forged layout resolve correctly. Contributors should record this as a composed T10.002 + T10.003 case rather than a single-primitive one.
Timeline (UTC)
| When | Event | OAK ref |
|---|---|---|
| Pre-2026-05-20 | Butter Bridge operates legitimately; cross-chain transfers authorised by oracle+multisig-signed messages; retry path re-submits failed transfers; retry verification derives a message integrity tag via keccak256(abi.encodePacked(...)) over dynamic fields |
(standing T10.002 surface) |
| 2026-05-20 | Attacker initiates a legitimate MAP→ETH bridge message (validly signed by oracle + multisig) | (genuine message — replay carrier) |
| 2026-05-20 | Attacker deploys a contract at a precomputed (CREATE2) address to interpose on the retry function | T10.002 setup (address manipulation) |
| 2026-05-20 | Attacker re-presents the transfer via retry with a re-arranged field layout whose abi.encodePacked hash collides with the accepted message; bridge processes the forged retry and mints 1,000,000,000,000,000 MAPO on Ethereum |
T10.002 + T10.003 execution (hash-collision + replay) |
| 2026-05-20 | Attacker swaps part of the minted supply into |
T5 outflow |
| 2026-05-20 | Blockaid publishes root-cause analysis (retry-verification abi.encodePacked weakness + replay + address manipulation) |
(third-party detection / forensic surface) |
| Post-2026-05-20 | MAP Protocol pauses all bridge operations; announces snapshot + new-token-contract migration to separate authentic balances from attacker-minted MAPO | (operator response / recovery) |
What defenders observed
- Pre-event (code / static-analysis layer): the retry-verification path computed a message integrity tag with
keccak256(abi.encodePacked(...))over two or more dynamic fields. This is a mechanically detectable anti-pattern — Slither'sencode-packed-collisiondetector and the Solidity documentation both warn that packing multiple dynamic types is not injective. A bridge audit that ran standard tooling against the verification path should have surfaced it. Defender lesson: treat anyabi.encodePackedfeeding a security-relevant hash as a hard finding; useabi.encode(length-prefixed, injective) or fixed-width fields for any value that participates in message identity or integrity. - At-event (on-chain signal): a single retry transaction produced a mint of one quadrillion MAPO — ~4.8M× the entire legitimate supply. A supply-monitoring indicator (mint event whose magnitude is implausible relative to historical supply, or a bridge mint with no matching source-chain lock/burn) would have flagged this in real time. The mint-vs-lock conservation check (the Verus lesson) would also have caught it independently.
- At-event (address signal): the attack relied on a contract deployed at a precomputed address to interpose on the retry function. A fresh contract whose address is referenced by a bridge retry message, deployed shortly before the retry call, is an elevated-risk pattern.
- Post-event: the drained value was small (~52.2 ETH) relative to the mint because the unbacked tokens could not be exited at scale; the price collapsed on discovery. The recovery path (snapshot + new token contract) is the standard remediation for an unbounded-mint event where the legitimate/illegitimate balance split is computable from chain history.
What this example tells contributors writing future Technique pages
- T10.002 needs a documented hash-encoding-ambiguity sub-class. It is mechanically distinct from initialisation (Nomad), account-validation (Wormhole), and economic-binding (Verus) failures: here the integrity tag itself is ambiguous. Record which sub-class a new T10.002 case belongs to — the audit guidance for "use
abi.encode, notabi.encodePacked" is specific to this one. - A known, lint-detectable footgun in a verification path is the most instructive kind of finding. Unlike a missing semantic invariant (Verus),
abi.encodePackedcollision is caught by off-the-shelf static analysis. The lesson is process, not insight: the tool exists; it was not run, or its finding was not actioned, on the verification path. - Replay and collision compose. Record Butter as T10.002 (collision) + T10.003 (replay): the genuine signed message was the replay carrier, and a used-message/nonce guard on the retry path would have broken the chain even with the collision present. Bridges should treat "a message may be retried" as a replay surface and gate it with a consumed-message set keyed on an injective identifier.
- Mint magnitude is a first-class signal for supply-side bridge exploits. When the constraint on extraction is exit liquidity rather than the mint size, the realised loss understates the event. Record both the realised figure (~$110K) and the notional supply event (1e15 MAPO) — the same notional-vs-realised discipline OAK applies to Hyperbridge.
Public references
[blockaidbutter2026]— Blockaid (@blockaid_) root-cause thread on X, 2026-05-20: Butter Bridge retry-message verification weakness;keccak256(abi.encodePacked(...))non-injective packing; message replay + precomputed-address manipulation; not a signature forgery / key compromise.[cryptotimesbutter2026]— Crypto Times, "MAP Bridge Exploit: 1 Quadrillion MAPO Minted in Cross-Chain Attack": https://www.cryptotimes.io/2026/05/21/map-bridge-exploit-1-quadrillion-mapo-minted-in-cross-chain-attack/[cryptobriefingbutter2026]— Crypto Briefing, "Map Protocol token MAPO plunges 96% after exploit mints quadrillion tokens": https://cryptobriefing.com/mapo-token-plunges-96-bridge-exploit/[ambcryptobutter2026]— AMBCrypto, "MAP Protocol plunges 96% after quadrillion-token MAPO exploit": https://ambcrypto.com/map-protocol-plunges-96-after-quadrillion-token-mapo-exploit-details/[currencyanalyticsbutter2026]— The Currency Analytics, "Butter Bridge Hack Mints 1 Quadrillion MAPO Tokens": https://thecurrencyanalytics.com/defi/butter-bridge-hack-mints-1-quadrillion-mapo-tokens-wiping-out-nearly-a-third-of-token-value-259299- Solidity documentation — non-standard packed mode (
abi.encodePacked) collision warning for multiple dynamic types; Slitherencode-packed-collisiondetector.
Discussion
Butter Bridge completes a four-way reference set for T10.002 alongside Nomad (trusted-root initialisation), Wormhole (signature/account validation) and Verus (economic-value binding). It is the only one of the four whose root cause is a named, tool-detectable Solidity anti-pattern: keccak256(abi.encodePacked(...)) over multiple dynamic fields. Where Verus teaches that auditors must articulate semantic invariants no single proof encodes, Butter teaches the opposite-feeling but equally important lesson — that a mechanical, already-documented footgun can still reach a production bridge's verification path, and that running standard static analysis on the verification code is not optional.
The case pairs naturally with Verus (examples/2026-05-verus-ethereum-bridge-source-amount-validation.md) as the two May-2026 bridge-mint/reserve failures where the cryptographic signing machinery worked as designed and the attacker's leverage was a gap in what the verified message was bound to (Verus) or how the verified message was identified (Butter). Both reinforce the corpus's "binding gaps" family: proof-to-message (Hyperbridge), message-to-source-backing (Verus), message-to-origin (CrossCurve, in examples/2026-q1-q2-crosschain-bridge-otc-cohort.md), and now message-to-integrity-tag (Butter). Contributors building out the T10 bridge cohort should treat these as a coherent family of binding failures distinct from key-compromise (T10.001) and pure replay (T10.003) — even though, as Butter shows, replay is frequently the carrier that makes a binding gap exploitable.