OAK — OnChain Attack Knowledge

Worked example · 2022-01

Qubit Bridge — BNB Smart Chain ↔ Ethereum — 2022-01-27

Loss
~$80M (~206,809 qXETH minted on the BNB Smart Chain side of the QBridge with no corresponding ETH ever transferred on the Ethereum side). The minted qXETH was used as collateral to borrow out the bridge's liquid assets (BNB, BUSD, CAKE, MDX, USDT, ETH, BTCB, DOT) on the Qubit lending market.
Recovery
none of material consequence. Qubit Finance offered a $2M bug-bounty / negotiation framing in the immediate aftermath and a $250k white-hat bounty that went unanswered. No funds were returned.
OAK Techniques observed
OAK-T10.002 (Message-Verification Bypass) — primary; the failure mode is the deposit-and-mint flow accepting a sentinel "address(0) means native ETH" path that did not actually verify any ETH had been transferred. OAK-T9.004 (Access-Control Misconfiguration) — secondary / mechanistic; the underlying defect is that deposit() and depositETH() shared a code path that did not separate "ETH was sent with this transaction" from "the token argument is the address(0) sentinel". OAK-T7.001 (Mixer-Routed Hop — proceeds were laundered through Tornado Cash).
Attribution
pseudonymous. The attacker wallet was funded via Tornado Cash and the proceeds were laundered onward through Tornado Cash. No public named-individual or named-cluster attribution has been issued. No OAK-G01 / state-actor public attribution.
Key teaching point
Qubit is structurally the first canonical "0x0 deposit acceptance" T10.002 case in OAK's worked-example catalogue. The defect is not novel as a class — bridges with native-asset sentinel-value handling have been a recurring 2021–2022 attack-surface — but Qubit is the case where the dollar magnitude (~$80M), the function-level clarity of the defect (deposit() vs depositETH() divergence), and the operational shape of the extraction (mint-then-borrow against the lending market) are all on the public record at high enough resolution to make it a teaching case.

Summary

On January 27, 2022, an attacker exploited a logic flaw in the QBridge contract (the cross-chain bridge between BNB Smart Chain and Ethereum operated by Qubit Finance, a BSC-side lending protocol). The QBridge contract exposed a deposit() function that accepted an arbitrary token address argument plus a resourceID. To support "deposit native ETH" semantics, the contract treated address(0) as a sentinel value indicating "the user is depositing native ETH" — the canonical pattern used by many bridges of the period.

The defect: the deposit() function accepted the address(0) sentinel and credited the user with bridged collateral (qXETH on the BSC side) without verifying that any ETH had actually been transferred along with the call. The dedicated depositETH() function was the path that was supposed to be used for native ETH deposits, and that function did include msg.value validation. But the attacker called deposit() directly, passing address(0) as the token address, with no ETH attached. The contract emitted a Deposit event indistinguishable from a real ETH-side deposit, the bridge's relayer picked it up, and the BSC side minted approximately 206,809 qXETH (~$80M at the time) to the attacker's address.

The attacker then deposited the freshly-minted qXETH as collateral into the Qubit lending market and borrowed out the entire pool of available liquid assets — BNB, BUSD, CAKE, MDX, USDT, ETH, BTCB, DOT — leaving the lending market technically insolvent against the synthetic collateral. The borrowed assets were swapped, bridged back to Ethereum, and routed through Tornado Cash.

For OAK's purposes, Qubit is the canonical worked example of the "0x0 deposit acceptance" subclass of T10.002. The defect is structurally adjacent to the Wormhole "missing guardian validation" pattern (examples/2022-02-wormhole.md) but distinct in shape: Wormhole's verification function failed to validate the authority of the message; Qubit's verification function failed to validate that an asset transfer underlay the deposit event. Both ladder up to T10.002 (operational classification: bridge with a verification flaw) and T9.004 (mechanistic classification: input that should have been treated as privileged is instead accepted unconditionally).

Timeline (UTC)

When Event OAK ref
Pre-event QBridge deposit() exposes an address(0) sentinel path for native-ETH deposits; the path does not validate msg.value > 0. The dedicated depositETH() does include the validation, but deposit() is reachable independently T10.002 / T9.004 latent flaw
2022-01-27 (T+0) Attacker calls deposit() on the Ethereum-side QBridge contract with token = address(0) and amount set to a large value, transferring no ETH; the contract emits a Deposit event as if a real native-ETH deposit had occurred T10.002 message forgery
2022-01-27 (T+0, repeated) Attacker repeats the call multiple times to scale up the spoofed deposit position; cumulative spoofed-deposit total reaches ~206,809 ETH-equivalent T10.002 scaled exploitation
2022-01-27 (relayer pickup) QBridge relayer treats the spoofed Deposit events as authentic and instructs the BSC side to mint the corresponding qXETH to the attacker's address T10.002 cross-chain mint without lock
2022-01-27 (T+~minutes) Attacker deposits the minted qXETH into the Qubit lending market as collateral and borrows out the entire available liquid-asset pool T5-equivalent liquidity drain
2022-01-27 (within hours) Qubit Finance acknowledges the incident; offers $2M bug-bounty / negotiation framing and subsequently a $250k white-hat bounty (response)
2022-01-27 onward Stolen assets bridged to Ethereum and routed through Tornado Cash T7.001 mixer-routed laundering
Subsequent No funds returned; no recovery; case settles into the public-record archive as a "0x0 deposit acceptance" canonical example (archived)

What defenders observed

  • Pre-event (audit / unit-test layer): the absence of msg.value > 0 (or, equivalently, the absence of an explicit "this code path is never reachable when the token argument is address(0)") in deposit() is a defect that a single targeted unit test — "call deposit() with token = address(0) and no ETH; expect revert" — would have caught immediately. The case is a textbook argument for adversarial unit tests at the bridge entry-points: every entrypoint should have at least one test of the form "call this function with the privileged-sentinel argument and the precondition for that path missing, and assert the call reverts."
  • Pre-event (formal-verification / property-based): a property of the form "for every successful Deposit event on the Ethereum side, the contract balance increased by an equivalent amount of the corresponding asset" would have flagged the issue at audit time. This is the property that bridges across the industry have been pushed to formalise post-Qubit, although the adoption rate as of v0.1 cutoff is uneven.
  • At-event: the spoofed Deposit events were on-chain-indistinguishable from authentic deposit events at the contract-emit layer; the pre-relayer detection signal was the contract-balance-vs-event-amount mismatch. Any monitoring of the form "for every Deposit event on the Ethereum side, verify that the contract's ETH balance increased by the event's amount field within the same transaction" would have flagged the spoofed events at the first occurrence. As of January 2022, this kind of per-bridge invariant monitoring was not industry-standard.
  • At-event (relayer-side): the relayer trusted the on-chain Deposit event without performing the same balance-delta check on its side. Relayer-side independent verification is a defensive layer that several post-2022 bridge architectures have introduced; Qubit's relayer of the period did not include it.
  • Post-event: no recovery primitive. The Tornado Cash laundering route absorbed the proceeds within hours; the lending-market liquidity drain was complete by that point.

What this example tells contributors writing future Technique pages

  • The "0x0 sentinel" failure mode is a recurring T10.002 subclass. Multiple bridges of the 2021–2022 period exposed a "native-asset is special-cased via address(0)" code path that did not robustly distinguish "the call passed address(0) and sent native asset" from "the call passed address(0) and sent nothing." Contributors writing future T10.002 examples should explicitly check for this pattern; if a bridge contract has a sentinel-value path for native assets, the contract's audit history should explicitly cite the msg.value > 0 invariant.
  • Mint-without-lock invariant monitoring is the runtime detection signal. As at Wormhole (examples/2022-02-wormhole.md), the post-extraction signal that catches T10.002 in production is the per-bridge invariant "every mint event on side A pairs with a balance-increase on side B in a bounded window." For Qubit, the more local-to-the-Ethereum-side variant is "every Deposit event corresponds to a same-transaction increase in the contract's balance of the deposited asset." Both invariants are operationally cheap; their adoption rate as of v0.1 cutoff remains uneven.
  • Attacker-funding via Tornado Cash is a 2022-era operational tell. Qubit, Wormhole (examples/2022-02-wormhole.md), and Ronin (examples/2022-03-ronin-bridge.md) all involve attackers funded through Tornado Cash on the entry side. By 2022 this was a sufficiently common pattern that "attacker wallet funded via Tornado Cash" is not, by itself, an attribution signal — it is the baseline-pseudonymous starting position for the 2022 bridge cohort. Contributors should not over-read the funding pattern as an attribution data-point.

Public references

  • [qubitpostmortem2022] (proposed) — Qubit Finance / QBridge official incident statement and post-mortem; primary operator-side source for the affected function path, the qXETH-mint geometry, and the bug-bounty / negotiation framing.
  • [certikqubit2022] (proposed) — CertiK contemporaneous forensic write-up; function-level walkthrough of the deposit() vs depositETH() divergence and the address(0) sentinel path.
  • [halbornqubit2022] (proposed) — Halborn forensic post-mortem; "0x0 deposit acceptance" framing and recommended invariant-monitoring posture.
  • [rektqubit2022] (proposed) — Rekt News write-up of the Qubit Finance / QBridge January 2022 incident; loss size, lending-market drain shape, Tornado-Cash laundering note.

Discussion

Qubit is structurally the first canonical "0x0 deposit acceptance" T10.002 case in OAK's worked-example catalogue. The defect is not novel as a class — bridges with native-asset sentinel-value handling have been a recurring 2021–2022 attack-surface — but Qubit is the case where the dollar magnitude (~$80M), the function-level clarity of the defect (deposit() vs depositETH() divergence), and the operational shape of the extraction (mint-then-borrow against the lending market) are all on the public record at high enough resolution to make it a teaching case.

The case sits one week before Wormhole (examples/2022-02-wormhole.md) on the calendar, and the two together are OAK's bridge-class pair from January–February 2022: Wormhole as the "missing guardian validation" canonical case, Qubit as the "missing native-asset deposit validation" canonical case. Both are T10.002 by operational classification and T9.004 by mechanistic classification; both involve the verification function accepting an input that the function should have treated as privileged.

A defender working on a 2022-era bridge contract who internalises both cases takes away two checklist items: (1) every authority involved in cross-chain message processing must be validated against the trusted set; (2) every native-asset-sentinel code path must validate that the corresponding native-asset transfer actually occurred. The two checklist items are independent — Wormhole satisfied (2) and failed (1); Qubit satisfied (1) and failed (2). The post-2022 bridge-architecture review process broadly internalised both, but the upgrade-path review (which is where Nomad subsequently failed — examples/2022-08-nomad-bridge.md) remains a separate axis where the industry's adoption rate is uneven.

Contributors writing future T10.002 examples with native-asset-sentinel patterns should reach for Qubit as the comparison reference: the function-level walk-through is unusually clean, and the lending-market drain shape that followed (mint synthetic collateral, then borrow out the real assets) is a recurring secondary attack pattern in bridges that are integrated with on-chain lending — a pattern that recurs at Cream, Hundred, and several other 2022–2023 cases.

Techniques demonstrated (3)