BSC WBNB allowance drain from unsafe spender approvals
Exploit Transactions
0x73d459ad3c926f5247a2018197d13b2a0acbc1fc46e1e54525c210a46130a56bVictim Addresses
0x766a0936ff0ad045d39871846194edbd5df63a58BSCLoss Breakdown
Similar Incidents
0x3Af7 burn-rate manipulation drains WBNB from BSC pool
37%BSC staking pool reentrancy drain
36%SwapX Stale-Allowance Drain
36%BankrollNetworkStack WBNB Flashswap Dividend Drain
35%YziLabs pool accounting flaw drains WBNB liquidity
35%MorningStar releaseReward flaw drains MSC and yields WBNB profit
35%Root Cause Analysis
BSC WBNB allowance drain from unsafe spender approvals
1. Incident Overview TL;DR
On BSC (chainid 56) at block 42357808, an unprivileged EOA 0xba35d089addac99a8e7bcd1a25712b1702623ae3 sent a single transaction to router contract 0xd310431e98412eb9a7c66808478bf08fdea81e2a. The router forwarded a call into helper contract 0x71cd31a564ff30ba61d7167a02babc1484034e84, which used an existing WBNB allowance from victim address 0x766a0936ff0ad045d39871846194edbd5df63a58 to execute WBNB.transferFrom into the router. The router then called WBNB.withdraw on the canonical WBNB contract 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c, unwrapping the captured WBNB to native BNB and sending the resulting BNB back to the attacker EOA in the same transaction. Native-balance diffs show that the attacker’s BNB holdings increased by 184093635600000000 wei while the WBNB contract’s native reserves decreased by 184162062600000000 wei, with the remainder covering gas and the attacker’s small input value.
2. Key Background
The incident involves the standard wrapped BNB (WBNB) contract on BSC at 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c, which holds native BNB and exposes ERC‑20 style approve/transferFrom as well as a withdraw(uint256) function to unwrap WBNB into BNB. The decompiled WBNB code shows that withdraw debits the caller’s internal WBNB balance and transfers an equal amount of native BNB from the contract to the caller:
// WBNB 0xbb4c...5095c — withdraw logic (decompiled)
function withdraw(uint256 arg0) public {
address var_a = address(msg.sender);
var_b = 0x03;
require(!storage_map_a[var_a] < arg0);
var_a = address(msg.sender);
var_b = 0x03;
storage_map_a[var_a] = storage_map_a[var_a] - arg0;
(bool success, bytes memory ret0) = address(msg.sender).transfer(arg0);
uint256 var_c = arg0;
emit Withdrawal(address(msg.sender), arg0);
}
Router contract 0xd310431e98412eb9a7c66808478bf08fdea81e2a and helper contract 0x71cd31a564ff30ba61d7167a02babc1484034e84 are publicly callable contracts that the attacker can target without any privileged roles. In the observed call trace, the router uses selector 0x0044010c as its entrypoint from the attacker EOA, and then invokes the helper with selector 0x23a69e75. The helper, in turn, queries the router for a token address and calls transferFrom on WBNB, spending tokens from a victim WBNB holder who previously granted an allowance to the helper (or an equivalent spender path).
// Seed transaction trace for 0x73d459ad3c926f5247a2018197d13b2a0acbc1fc46e1e54525c210a46130a56b (excerpt)
{
"calls": [
{
"from": "0xd310431e98412eb9a7c66808478bf08fdea81e2a",
"input": "0x23a69e75…",
"to": "0x71cd31a564ff30ba61d7167a02babc1484034e84",
"type": "CALL",
"value": "0x0",
"calls": [
{
"from": "0x71cd31a564ff30ba61d7167a02babc1484034e84",
"input": "0xd21220a7",
"to": "0xd310431e98412eb9a7c66808478bf08fdea81e2a",
"type": "STATICCALL"
},
{
"from": "0x71cd31a564ff30ba61d7167a02babc1484034e84",
"input": "0x23b872dd…00000000766a0936ff0ad045d39871846194edbd5df63a58…00000000d310431e98412eb9a7c66808478bf08fdea81e2a…000000000000000000000000000000000000000000000000028e466b92605200",
"to": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"type": "CALL"
}
]
}
]
}
Victim address 0x766a0936ff0ad045d39871846194edbd5df63a58 holds WBNB and has granted a WBNB allowance that permits the helper to call WBNB.transferFrom on its balance. The on-chain APIs used in data collection could not retrieve full historical transaction lists for the attacker, router, helper, or victim addresses (due to Etherscan HTTP 403 and QuickNode JSON‑RPC method errors), so we cannot see when the approval and deposits were made, but the successful transferFrom and withdraw calls in the trace are sufficient to establish that the necessary pre‑state existed.
3. Vulnerability Analysis & Root Cause Summary
The root cause is a publicly callable helper/router path that allows any unprivileged EOA to leverage an existing WBNB allowance to convert a victim’s WBNB into native BNB and send the proceeds to the attacker within a single transaction. WBNB itself behaves according to its expected design: it tracks internal balances, honors approve/transferFrom, and unpacks value via withdraw to msg.sender. The exploit arises from how the helper and router compose these primitives: the helper spends WBNB from the victim into the router, and the router immediately withdraws that WBNB and forwards all resulting BNB to the attacker EOA. From the publicly reconstructible pre‑state immediately before block 42357808, this behavior constitutes an anyone-can-take (ACT) opportunity: any EOA capable of crafting the same calldata can replicate the attack without needing privileged roles, validator control, or off-chain secrets. The vulnerability class is improper use of token allowances through an unguarded helper/router flow that routes value to arbitrary third parties.
4. Detailed Root Cause Analysis
The explicit security invariant relevant to this incident is:
For any WBNB holder address H and any unprivileged EOA A, there should be no transaction crafted solely by A that (i) spends H’s WBNB via
WBNB.transferFromandWBNB.withdrawand (ii) delivers the resulting BNB directly to A, without any signature from H in that transaction.
This invariant is violated in the seed transaction 0x73d459ad3c926f5247a2018197d13b2a0acbc1fc46e1e54525c210a46130a56b on BSC. The reconstructed call sequence from tx_trace_callTracer.json is:
- The attacker EOA
0xba35d089addac99a8e7bcd1a25712b1702623ae3calls router0xd310431e98412eb9a7c66808478bf08fdea81e2awith selector0x0044010cand small input value (0xdc0wei). - The router issues a
CALLto helper0x71cd31a564ff30ba61d7167a02babc1484034e84with selector0x23a69e75, passing among its arguments the router address, victim address0x766a0936ff0ad045d39871846194edbd5df63a58, and an amount0x028e466b92605200. - Inside that helper call:
- The helper performs a
STATICCALLto the router (selector0xd21220a7), receiving0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095cas the token address. - The helper then calls WBNB at
0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095cwith selector0x23b872dd(transferFrom), moving0x028e466b92605200units of WBNB from0x766a0936ff0ad045d39871846194edbd5df63a58to the router0xd310431e98412eb9a7c66808478bf08fdea81e2a. This call succeeds, which implies that the pre‑state includes a sufficient allowance from the victim to the helper (or equivalent spender path).
- The helper performs a
// transferFrom and withdraw path (excerpt)
{
"from": "0x71cd31a564ff30ba61d7167a02babc1484034e84",
"to": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"input": "0x23b872dd000000000000000000000000766a0936ff0ad045d39871846194edbd5df63a58000000000000000000000000d310431e98412eb9a7c66808478bf08fdea81e2a000000000000000000000000000000000000000000000000028e466b92605200",
"type": "CALL",
"value": "0x0"
},
{
"from": "0xd310431e98412eb9a7c66808478bf08fdea81e2a",
"to": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"input": "0x70a08231…d310431e98412eb9a7c66808478bf08fdea81e2a",
"type": "STATICCALL"
},
{
"from": "0xd310431e98412eb9a7c66808478bf08fdea81e2a",
"to": "0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c",
"input": "0x2e1a7d4d000000000000000000000000000000000000000000000000028e466b92605200",
"type": "CALL"
}
- After WBNB has been transferred into the router, the router invokes its own function with selector
0x7ddd1537, which:- Calls
WBNB.balanceOf(router)via0x70a08231, observing a balance of0x028e466b92605201. - Calls
WBNB.withdraw(0x028e466b92605200)via selector0x2e1a7d4d, causing the WBNB contract to send0x028e466b92605200wei of native BNB (decimal184162062600000000) from its reserves to the router.
- Calls
- Finally, the router sends
0x028e466b92605fc0wei (184162062600003520wei) to the attacker EOA0xba35d089addac99a8e7bcd1a25712b1702623ae3.
Because only the attacker EOA signs this transaction, and the victim 0x766a0936ff0ad045d39871846194edbd5df63a58 does not participate in the transaction’s authorization, the helper/router path lets an arbitrary EOA convert the victim’s WBNB allowance into BNB for its own benefit. WBNB’s own logic is consistent with a standard wrapped-asset implementation; the exploitable condition is that the helper and router combine transferFrom and withdraw in a way that routes the unwrapped BNB to an attacker-controlled EOA rather than to the victim or a tightly scoped beneficiary.
The primary vulnerable components are:
- Helper contract
0x71cd31a564ff30ba61d7167a02babc1484034e84, whose selector0x23a69e75flow, as observed in the trace, reads the token address from the router and executestransferFromon WBNB from the victim to the router. - Router contract
0xd310431e98412eb9a7c66808478bf08fdea81e2a, whose0x7ddd1537function withdraws WBNB held by the router and forwards the resulting BNB to the attacker EOA. - The pre-existing WBNB allowance from victim
0x766a0936ff0ad045d39871846194edbd5df63a58to the helper (or equivalent spender), which enables thetransferFromto succeed without any per‑call confirmation by the victim.
The ACT exploit conditions distilled from the artifacts are:
- Victim
0x766a0936ff0ad045d39871846194edbd5df63a58holds at least0x028e466b92605200WBNB on0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c. - The victim has granted a WBNB allowance to the helper
0x71cd31a564ff30ba61d7167a02babc1484034e84(or to an equivalent spender used in the helper/router path) sufficient for thetransferFromto succeed. - The router and helper contracts are deployed with the runtime code reflected in the decompilations and remain publicly callable.
- An unprivileged EOA can submit a transaction equivalent to the seed tx, targeting the router with the same calldata and gas, to realize the same sequence of calls and state transitions.
5. Adversary Flow Analysis
The adversary-related cluster and victim candidate identified from the artifacts are:
- Adversary EOA:
0xba35d089addac99a8e7bcd1a25712b1702623ae3(sender and recipient of profit in the seed transaction). - Router contract:
0xd310431e98412eb9a7c66808478bf08fdea81e2a(direct callee of the attacker and orchestrator of helper and WBNB interactions). - Helper contract:
0x71cd31a564ff30ba61d7167a02babc1484034e84(performstransferFromfrom the victim to the router). - Victim WBNB holder (candidate):
0x766a0936ff0ad045d39871846194edbd5df63a58.
The adversary executes a single lifecycle stage:
- Stage: Adversary single‑tx execution
- Chain: BSC (56)
- Transaction:
0x73d459ad3c926f5247a2018197d13b2a0acbc1fc46e1e54525c210a46130a56b - Block:
42357808 - Mechanism: Public helper/router path abusing WBNB allowance
End‑to‑end flow:
- The attacker EOA funds itself and constructs calldata for router function
0x0044010c, embedding the helper address, helper selector, router address, victim address, amount, and a follow‑up router function (0x7ddd1537) to execute after the helper call. - The router receives the call, decodes the parameters, and calls helper
0x71cd31a564ff30ba61d7167a02babc1484034e84with selector0x23a69e75. - The helper reads the WBNB token address from the router via a
STATICCALL, then calls WBNB’stransferFromfrom the victim to the router for0x028e466b92605200units. - Control returns to the router, which calls its
0x7ddd1537function, reading its WBNB balance viabalanceOfand then callingwithdrawon WBNB for the same amount, receiving an equal amount of BNB from the WBNB contract. - The router immediately forwards almost all of this BNB (
184162062600003520wei) to the attacker EOA, retaining only enough to cover gas and its own call‑level needs. - Gas accounting based on
tx_metadata.json,tx_receipt.json, andbalance_diff.jsonshows that after subtracting gas fees at 1 gwei and the attacker’s tiny input, the attacker ends the transaction with a net gain of184093635600000000wei of BNB.
This strategy is an ACT opportunity because any unprivileged EOA with knowledge of the helper/router interfaces and the victim’s outstanding allowance can replicate the same calldata and transaction structure to drain the victim’s WBNB into BNB for its own benefit, as long as the pre‑state conditions hold.
6. Impact & Losses
The on‑chain impact for the observed exploit transaction is:
- WBNB reserves at
0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095close184162062600000000wei of native BNB, as recorded inbalance_diff.json. - The economic value of victim
0x766a0936ff0ad045d39871846194edbd5df63a58’s WBNB holdings decreases by an amount equal to the WBNB converted and withdrawn to BNB, although the exact ERC‑20 balance delta for the victim is not included in the provided diff. - Attacker EOA
0xba35d089addac99a8e7bcd1a25712b1702623ae3realizes a net profit of184093635600000000wei of BNB after fees. - No broader protocol‑level invariant break in WBNB itself or systemic price impact is evident from the available artifacts; the harm is concentrated in the misdirected use of the victim’s allowance and the associated reserve outflow.
In tokenized form, the primary quantified loss is:
- Token: BNB
- Amount:
-184162062600000000wei (lost from WBNB reserves, corresponding one‑for‑one to BNB unwrapped and sent out)
7. References
- Seed transaction: BSC tx
0x73d459ad3c926f5247a2018197d13b2a0acbc1fc46e1e54525c210a46130a56b(metadata, receipt, and geth callTracer trace). - WBNB contract: decompiled code for
0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c, includingwithdraw(uint256)and ERC‑20 functions. - Router contract: decompiled code for
0xd310431e98412eb9a7c66808478bf08fdea81e2a, including the0x7ddd1537flow that withdraws WBNB and forwards BNB. - Helper contract: decompiled code for
0x71cd31a564ff30ba61d7167a02babc1484034e84and runtime ABI information showing selector0x23a69e75is used in the exploit path. - Balance diffs:
balance_diff.jsonfor the seed transaction, detailing native BNB balance changes for the attacker and WBNB contract.