QBridge on Ethereum exposed a legacy deposit() function alongside the newer depositETH() entry point. The function relied on a custom SafeToken.safeTransferFrom() helper that used a raw low-level call() to the token contract, never asserting that the target address contained bytecode (no extcodesize check). The attacker passed tokenAddress = address(0), which was already whitelisted to represent native ETH for accounting purposes, and supplied amount = 200 ETH while sending zero msg.value. Because address(0) is an EOA with no code, the call() returned success with empty returndata; safeTransferFrom did not revert, and the contract emitted a Deposit event as if 200 ETH had been received. The BSC relayer indexed that event and minted qXETH on the destination chain. The attacker repeated the deposit thirteen times to accumulate ~206,809 qXETH and borrowed BNB and other assets against it on Qubit's lending market.
Reproducible Foundry test fork from SunWeb3Sec/DeFiHackLabs. Clone the repo, run forge test against the file path above, and replay the exploit against a mainnet fork at the historical block. Use for reproduction only — not for live targets.
Classification: Protocol Logic. Technique: Transfer Logic Exploit. Bridge hack. Target type: DeFi Protocol. Affected chains: BSC. Implementation language: Solidity.
- chain
- bsc
- protocol
- Qubit
- bug_class
- bridge
- date_occurred
- 2022-01-28
- loss_usd
- $80,000,000
- classification
- Protocol Logic
- technique
- Transfer Logic Exploit
- target_type
- DeFi Protocol
- language
- Solidity
- bridge_hack
- YES
- source_id
- dl:516