Worked example · 2026-07
Wanchain Cardano bridge — 14 variable-length fields concatenated without separators make the signed message non-injective, so a signature for 3,110 NIGHT authorises 203,001,692 — Wanchain / Midnight NIGHT (Cardano ⇄ BNB Chain) — 2026-07-20/21
Summary
Wanchain operates a cross-chain bridge connecting Cardano and BNB Chain, used among other things to move NIGHT, the token of the Midnight network. Bridge withdrawals are authorised by a 25-node validator set with a 17-signature threshold; a withdrawal is honoured when a validator-signed message attests to it.
The Cardano-side TreasuryCheck validator constructed that signed message by concatenating 14 variable-length redeemer fields directly, with no separators and no length prefixes. This makes the encoding non-injective — moving bytes across a field boundary produces a different set of field values that serialise to an identical byte string. Two economically unrelated withdrawals can therefore share a single hash and a single valid signature.
An attacker took a legitimate signature that authorised approximately 3,110 NIGHT on BNB Chain and presented it on Cardano with a different arrangement of the redeemer fields — one whose parse yielded a withdrawal of 203,001,692 NIGHT. The validator recomputed the hash over the supplied fields, matched it against the signature, and approved.
Over roughly nine minutes, four withdrawals removed approximately 203.0M, 129.6M, 120.4M, and 62.1M NIGHT — about 515.2M NIGHT in total, or 97.8% of the reserve. Wanchain took the bridge offline and began investigating. The Midnight Foundation confirmed the Midnight blockchain was not affected. The exploit triggered a selloff that took NIGHT down more than 30% to a record low near $0.016.
Timeline (UTC)
| When | Event | OAK ref |
|---|---|---|
| (standing) | TreasuryCheck builds the signed message by concatenating 14 variable-length redeemer fields with no separators or length prefixes; contract contains SerialiseData but does not use it on the signing path |
(standing T10.002 surface) |
| (prior) | Validator set legitimately signs an authorisation for ~3,110 NIGHT on BNB Chain | (legitimate authorisation) |
| 2026-07-20/21 | Attacker re-presents that signature on Cardano with a different redeemer-field arrangement decoding to 203,001,692 NIGHT; hash matches, signature verifies | T10.002 / T10.003 exploitation |
| same window (~9 min) | Four withdrawals of ~203.0M, ~129.6M, ~120.4M, ~62.1M NIGHT — ~515.2M total, ~97.8% of reserve — land in one attacker wallet | T10.002 extraction |
| after | Wanchain takes the bridge offline and opens an investigation; Midnight Foundation confirms the Midnight chain is unaffected; NIGHT falls >30% to ~$0.016 | (operator response) |
| after | Attacker consolidates into a primary Cardano wallet and liquidates ~90% of the haul via Cardano DEXs and DeFi protocols | T7.007 |
| 2026-07-31 | Wanchain publicly offers a 10% white-hat bounty for return of the remaining 90% by a 2026-08-06 deadline, pledging not to pursue civil claims if accepted | (negotiated-return offer) |
What defenders observed
- Pre-event (the encoding, not the key management, was the reviewable artefact). Everything a conventional bridge security review looks at was in good order: a 25-node validator set, a 17-of-25 threshold, no compromised keys. The defect was in a serialisation routine, and it is statically visible — a concatenation of variable-length fields with no delimiters is a structural property of the code, not a runtime condition. Reviews that treat "how is the message encoded before it is hashed?" as a first-class question catch this class; reviews that stop at signing policy do not.
- Pre-event (
SerialiseDatawas present and unused). The safe primitive was already a dependency. That is a recurring shape: the codebase contains the canonical encoder, and the signing path takes a hand-rolled shortcut instead. Grepping for a canonical-serialisation function and checking whether the hash-and-sign path actually calls it is a cheap, mechanical audit step. - At-event (the amount ratio is the detection signal). A withdrawal of 203,001,692 NIGHT against an authorisation for 3,110 is a 65,000× discrepancy. A bound comparing the withdrawal to plausible per-authorisation size — or to a fraction of reserve — would have rejected all four transactions regardless of signature validity. A single withdrawal taking a double-digit percentage of a bridge reserve should never clear without a circuit breaker (M04, M05).
- At-event (97.8% of reserve in nine minutes). The reserve had no rate limit and no per-window cap. Nine minutes is ample for an automated pause if any threshold existed to trip; there was none, so the drain ran to near-completion.
- Response (the honest-validator paradox). No validator misbehaved and no key was compromised, so every key-rotation and quorum-hardening response available to the operator addresses a failure that did not occur. The only fix that closes this is changing the encoding, which is why correctly classifying the mechanism matters operationally rather than just taxonomically.
Public references
[cryptotimeswanchaininsight2026]— The Crypto Times, "Inside Wanchain's $10M NIGHT Bridge Exploit" (the non-injective encoding, 14 variable-length fields without separators or length prefixes,TreasuryCheckvalidator, the 3,110-NIGHT BNB Chain signature reused on Cardano, the four withdrawal amounts, 25 nodes / 17 signatures, unusedSerialiseDataand theSha3_256(SerialiseData(…))fix): https://www.cryptotimes.io/insights/wanchain-night-bridge-exploit-signature-flaw/[cryptotimeswanchain2026]— The Crypto Times, "Wanchain Cardano Bridge Exploited, Hackers Stole $10M in NIGHT Tokens" (2026-07-21 dating, ~$10M valuation, Cardano ⇄ BNB Chain scope): https://www.cryptotimes.io/2026/07/21/wanchain-cardano-bridge-exploited-hackers-stole-10m-in-night-tokens/[coingapewanchain2026]— CoinGape, "Wanchain Cardano Bridge Breached in $13M Hack, 515M NIGHT Tokens Drained" (the ~$13M valuation, 515M NIGHT figure): https://coingape.com/wanchain-cardano-bridge-breached-in-13m-hack-515m-night-tokens-drained/[tokenpostwanchain2026]— TokenPost, "Wanchain Bridge Hack Drains $13M in NIGHT Tokens, Cardano Midnight Network Remains Secure" (Midnight network unaffected, bridge taken offline): https://www.tokenpost.com/news/investing/22221[coindeskwanchain2026]— CoinDesk, "Midnight's NIGHT token rebounds 19% after Wanchain bridge hack" (price impact and ~19% rebound): https://www.coindesk.com/business/2026/07/22/midnight-token-rebounds-after-wanchain-bridge-hack-hoskinson-calls-for-industry-overhaul[cryptotimesweek0726]— The Crypto Times, "Crypto Loses Over $47M in a Week as AFX Trade, Wanchain, Verus Get Hacked" (weekly cohort context, 515.2M NIGHT / ~$10M line): https://www.cryptotimes.io/2026/07/26/crypto-loses-over-47m-in-a-week-as-afx-trade-wanchain-verus-get-hacked/[cryptotimeswanchaindeadline2026]— The Crypto Times, "Wanchain Sets August 6 Deadline for Cardano Bridge Hacker" (the 2026-07-31 negotiated-return offer: a 10% white-hat bounty for returning 90% of the stolen NIGHT by 2026-08-06 with no civil claims pursued, and the finding that the attacker had consolidated into a primary Cardano wallet and already liquidated ~90% of the haul through DEXs and DeFi protocols on the network): https://www.cryptotimes.io/2026/07/31/wanchain-sets-august-6-deadline-for-cardano-bridge-hacker/
Discussion
This is the Cardano-side twin of examples/2026-05-map-protocol-butter-bridge-encodepacked-collision.md, and reading the two together is the point. MAP Protocol's Butter bridge lost funds to abi.encodePacked collisions — Solidity's packed encoder concatenating dynamic types without length prefixes so that ("a","bc") and ("ab","c") produce identical bytes. Wanchain lost funds to the same mathematical defect expressed in Plutus rather than Solidity, on a validator that had the length-delimited alternative available and did not call it. Neither is an EVM quirk. Non-injective encoding is a property of concatenation, not of a language, and any chain whose tooling offers both a packed and a canonical encoder will keep producing this class until reviewers treat the choice between them as security-relevant.
The second thing worth extracting is how thoroughly this defeats the standard bridge-security narrative. The industry has spent several years converging on "decentralise the signer set, raise the threshold" as the answer to bridge risk, and by that metric Wanchain scored well: 25 independent nodes, a 17-signature threshold, no single point of key failure. All of that was intact, and none of it was relevant. Threshold cryptography answers who authorised this; it has nothing to say about what the authorisation means once the message is ambiguous. A defender modelling this bridge's risk from validator-set decentralisation alone would have rated it strong right up to the moment 97.8% of the reserve left in nine minutes.
Contributors documenting future cases in this class should record the authorised-amount to withdrawn-amount ratio explicitly — here 3,110 against 203,001,692. That ratio is the cleanest artefact distinguishing encoding-ambiguity reuse from ordinary key compromise: a stolen key produces withdrawals that are unauthorised but internally coherent, while encoding ambiguity produces withdrawals that carry a real signature for a completely different number.