Unauthenticated Pancake Callback Drain
Exploit Transactions
0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2Victim Addresses
0x64dd59d6c7f09dc05b472ce5cb961b6e10106e1dBSCLoss Breakdown
Similar Incidents
STRAC Callback Drain
42%BSC Callback Auth Drain
41%Annex Liquidator WBNB Drain
36%Transit Router V5 Drain
35%EEECOIN Public Helper LP Drain
35%MetaverseToken fee misconfiguration drains USDT from Pancake pair
34%Root Cause Analysis
Unauthenticated Pancake Callback Drain
1. Incident Overview TL;DR
In BNB Smart Chain block 21297410, EOA 0xee286554f8b315f0560a15b6f085ddad616d0601 sent transaction 0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2 to helper contract 0x5cb11ce550a2e6c24ebfc8df86c5757b596e69c1. That helper repeatedly invoked pancakeCall(address,uint256,uint256,bytes) on callback contract 0x64dd59d6c7f09dc05b472ce5cb961b6e10106e1d, causing the callback contract to transfer out all of its balances in USDT, WBNB, BUSD, USDC, BTCB, and ETH to the adversary EOA.
The root cause is an unauthenticated AMM callback path. The victim contract exposes pancakeCall and uniswapV2Call but does not verify that msg.sender is a real trusted pair before using msg.sender.token0() or msg.sender.token1() to choose which token to transfer. Any unprivileged actor can therefore deploy a fake pair-like contract, return arbitrary token addresses from those selectors, and drain the callback contract whenever it holds token balances.
2. Key Background
pancakeCall and uniswapV2Call are flash-swap callback entrypoints used by PancakeSwap and Uniswap V2 style pairs. They are only safe when the callee authenticates the caller as the exact pair expected for the swap. Without that check, any contract that implements the same selector surface can impersonate a pair.
The helper contract in the seed transaction only needed three relevant behaviors: expose token0(), expose token1(), and invoke the victim callback. The trace shows that this was enough to satisfy the victim contract's assumptions. Once the victim trusted the helper as if it were a pair, the helper could steer the victim into selecting attacker-chosen token contracts and executing outbound ERC20 transfers.
3. Vulnerability Analysis & Root Cause Summary
This is an ATTACK-category access control failure in a value-bearing helper contract. The vulnerable component is the callback contract at 0x64dd59d6c7f09dc05b472ce5cb961b6e10106e1d, specifically its pancakeCall(address,uint256,uint256,bytes) and uniswapV2Call(address,uint256,uint256,bytes) entrypoints.
The relevant invariant is simple: a DEX callback must not move assets unless msg.sender is the legitimate pair that initiated a real swap. Independent bytecode inspection confirms that the callback path beginning near bytecode offset 0x010a branches on the amounts, queries CALLER.token0() or CALLER.token1(), and then builds ERC20 transfer calls using the returned address, but it does not authenticate the caller first. The same bytecode contains owner-gated admin logic elsewhere, which shows that access control existed in the contract generally but was omitted on the callback path that actually moves funds.
4. Detailed Root Cause Analysis
The seed transaction metadata shows the top-level flow:
{
"from": "0xee286554f8b315f0560a15b6f085ddad616d0601",
"to": "0x5cb11ce550a2e6c24ebfc8df86c5757b596e69c1",
"hash": "0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2",
"blockNumber": "0x144f902"
}
Origin: seed transaction metadata.
The transaction trace then shows the helper calling the victim callback six times. For each call, the victim first staticcalls the helper for token0() and then transfers the full token balance to the attacker recipient encoded in calldata:
0x64dD59D6C7f09dc05B472ce5CB961b6E10106E1d::pancakeCall(..., 25912948173777791158265, 0, ...)
0x5cB11ce550a2E6c24EBFC8DF86C5757b596e69c1::token0() [staticcall]
0x55d398326f99059fF775485246999027B3197955::transfer(
0xEE286554F8b315F0560A15b6f085dDad616D0601,
25912948173777791158265
)
Origin: seed transaction trace.
The same pattern repeats for WBNB, BUSD, USDC, BTCB, and ETH in the same transaction. The trace is therefore sufficient to show that the caller-controlled helper dictated the token address and that the victim then executed the transfers from its own balance.
Independent disassembly of the live victim bytecode matches that behavior. The callback path at 0x010a issues a STATICCALL to CALLER with selector 0x0dfe1681 (token0()) or 0xd21220a7 (token1()), then prepares selector 0xa9059cbb (transfer(address,uint256)) and performs a CALL to the returned token address:
00000132: CALLER
00000149: PUSH4 0x0dfe1681
...
0000016b: STATICCALL
...
0000022b: PUSH4 0xa9059cbb
...
0000029d: CALL
Origin: validator bytecode disassembly of 0x64dd59d6c7f09dc05b472ce5cb961b6e10106e1d.
No preceding pair or factory authentication appears on that execution path. That omission is the concrete breakpoint that turns a normal callback into a public drain primitive.
5. Adversary Flow Analysis
The adversary flow is fully contained in one transaction:
- The EOA
0xee286554f8b315f0560a15b6f085ddad616d0601calls helper contract0x5cb11ce550a2e6c24ebfc8df86c5757b596e69c1. - The helper reads token balances on the victim contract and invokes
pancakeCallonce per token withamount0equal to the full victim balance. - Inside each callback, the victim treats the helper as if it were a trusted pair, asks it for
token0()ortoken1(), and uses that address as the ERC20 to transfer. - The victim transfers the full token balance to the attacker recipient encoded in calldata.
The trace excerpt below shows the repeated six-call draining sequence:
0x64dD59...::pancakeCall(... USDT amount ...)
0x64dD59...::pancakeCall(... WBNB amount ...)
0x64dD59...::pancakeCall(... BUSD amount ...)
0x64dD59...::pancakeCall(... USDC amount ...)
0x64dD59...::pancakeCall(... BTCB amount ...)
0x64dD59...::pancakeCall(... ETH amount ...)
Origin: seed transaction trace summary lines.
This sequence satisfies the ACT model because it requires no privileged key material, no private orderflow, and no dependency on attacker-owned on-chain artifacts beyond a fresh spoofing contract with public selectors.
6. Impact & Losses
The callback contract at 0x64dd59d6c7f09dc05b472ce5cb961b6e10106e1d was fully depleted of six ERC20 balances. The balance-diff artifact records the victim balances dropping to zero and the attacker EOA receiving the same raw amounts.
[
{"token_symbol": "USDT", "amount": "25912948173777791158265", "decimal": 18},
{"token_symbol": "WBNB", "amount": "327931283327916980816", "decimal": 18},
{"token_symbol": "BUSD", "amount": "22307554466878046228172", "decimal": 18},
{"token_symbol": "USDC", "amount": "5160324984279773039298", "decimal": 18},
{"token_symbol": "BTCB", "amount": "14990282011559361", "decimal": 18},
{"token_symbol": "ETH", "amount": "97450591261976269", "decimal": 18}
]
Origin: root cause loss summary and seed balance diff.
The attacker paid only 4904355000000000 wei of BNB in gas according to the native balance delta.
7. References
- Seed transaction
0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2. - Victim callback contract
0x64dd59d6c7f09dc05b472ce5cb961b6e10106e1d. - Helper contract
0x5cb11ce550a2e6c24ebfc8df86c5757b596e69c1. - Seed transaction metadata in
/workspace/session/artifacts/collector/seed/56/0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2/metadata.json. - Seed trace in
/workspace/session/artifacts/collector/seed/56/0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2/trace.cast.log. - Seed balance diff in
/workspace/session/artifacts/collector/seed/56/0xd48758ef48d113b78a09f7b8c7cd663ad79e9965852e872fdfc92234c3e598d2/balance_diff.json.