BSC PoolWithdraw Signature-Bypass Drains USDT Pool
Exploit Transactions
0x3d936c59c9d446ee222361acc820be47054aea45f9f5fc92482fe973a596e4750x0d9e4478567aa33dad3bd7c9a79de5f2afc9c7037c026795aa838f5ab834ca800x91f4526052060d7137919a8e2bb3ce6c2169e5a376ab002c4745f69841cfd784Victim Addresses
0x20dbf42970eb3fabe62615534c4ef15fd4d59596BSC0x79f9b0b81e08efc3690bb78611620cb1b708fccbBSCLoss Breakdown
Similar Incidents
BNB-chain constructor exploit drains full USDT pool balance
36%Public Mint Drains USDT Pair
36%Public mint flaw drains USDT from c3b1 token pool
35%BSC staking pool reentrancy drain
35%0x3Af7 burn-rate manipulation drains WBNB from BSC pool
34%Marketplace proxy 0x9b3e9b92 bug drains USDT and mints rewards
34%Root Cause Analysis
BSC PoolWithdraw Signature-Bypass Drains USDT Pool
1. Incident Overview TL;DR
An unprivileged adversary repeatedly drained USDT from pool contract 0x20dbf42970eb3fabe62615534c4ef15fd4d59596 on BSC by calling poolWithdraw(address,uint256,address,uint256,address[],uint256,bytes[]) (0xc7e36d91) with allSigners=[] and signatures=[].
The root cause is a function-level authorization gap: poolWithdraw allows value transfer and internal pool-balance decrement without enforcing the configured signer quorum (requiredSignatures=3) when signer arrays are empty.
The attack is ACT (is_act=true) because it is permissionless and reproducible from unrelated EOAs using public on-chain data only.
2. Key Background
- Victim proxy:
0x20dbf42970eb3fabe62615534c4ef15fd4d59596. - Delegate implementation observed in traces:
0x79f9b0b81e08efc3690bb78611620cb1b708fccb. - Target token: USDT
0x55d398326f99059ff775485246999027b3197955. - Runtime selector mapping identifies:
0xc7e36d91->poolWithdraw(address,uint256,address,uint256,address[],uint256,bytes[])0x43251e03->poolFeeWithdraw(address,uint256,address,uint256,uint256,address[],bytes[])
- Sibling function behavior differs under the same context:
poolFeeWithdrawrejects empty signer arrays (invalid allSigners length), whilepoolWithdrawsucceeds.
Evidence snapshot (BSC pre-state simulation at block 0x4fbb1cd):
{
"requiredSignatures": "3",
"attacker_whitelist": "false",
"attacker_isAllowedSigner": "false",
"poolWithdraw_empty_signers": { "status": "success" },
"poolFeeWithdraw_empty_signers": {
"status": "revert",
"error": "execution reverted: invalid allSigners length"
}
}
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK-class authorization failure. The intended invariant is: any pool asset withdrawal must require valid authorization (authorized caller and/or signer quorum). In the observed implementation path, poolWithdraw can be executed with empty allSigners and signatures arrays, even when requiredSignatures=3. The call then proceeds to transfer USDT out of the victim and decrement pool accounting. Trace evidence confirms execution enters the proxy and delegatecalls into implementation 0x79f9... with selector 0xc7e36d91, then performs ERC20 transfer to attacker-controlled receivers. The same pre-state confirms attacker addresses are not whitelisted and not allowed signers. Because this path is reachable by arbitrary EOAs/contracts without privileged keys, the exploit is permissionless and repeatable.
4. Detailed Root Cause Analysis
- Pre-state at block
83603917(0x4fbb1cd) is publicly reconstructible and shows signer policy active (requiredSignatures=3) with positive victim USDT pool balance. - The adversary submits a normal L1 transaction calling
poolWithdrawon victim proxy0x20db...with:- token = USDT,
- receiver = attacker-controlled address,
- non-expired
expireTime, allSigners=[],signatures=[].
- Trace confirms victim proxy forwards by
DELEGATECALLto implementation0x79f9..., still with selector0xc7e36d91. - Execution succeeds (no revert), emits
PoolWithdraw, transfers USDT from victim, and decreases internal pool balance. - Independent simulation from unrelated address
0x1111111111111111111111111111111111111111reproduces the same success with empty arrays; under identical conditionspoolFeeWithdrawreverts withinvalid allSigners length.
Representative execution snippet (exploit tx 0x0d9e... call trace):
{
"from": "0xd25f43449231218c8be3871073938fcc2202ab56",
"to": "0x20dbf42970eb3fabe62615534c4ef15fd4d59596",
"type": "CALL",
"input_prefix": "0xc7e36d91",
"nested_call": {
"to": "0x79f9b0b81e08efc3690bb78611620cb1b708fccb",
"type": "DELEGATECALL",
"input_prefix": "0xc7e36d91"
}
}
Invariant break and breakpoint:
- Invariant: decreasing
poolBalances[token]and transferring pool assets must require valid signer quorum/authorization. - Breakpoint:
poolWithdrawaccepts empty signer/signature arrays and still performs state-changing withdrawal transfer.
5. Adversary Flow Analysis
Stage A - Unauthorized pool withdrawal
0x0d9e4478567aa33dad3bd7c9a79de5f2afc9c7037c026795aa838f5ab834ca80(block83603918): withdraws59,974.609375USDT to sender0xd25f....0x3d936c59c9d446ee222361acc820be47054aea45f9f5fc92482fe973a596e475(block83574859): withdraws59,781.25USDT to sender0x8c98....0x91f4526052060d7137919a8e2bb3ce6c2169e5a376ab002c4745f69841cfd784(block83630514): helper0xebd...withdraws59,991.77USDT and forwards to0xc6e....
Stage B - Profit realization
- In
0x0d9e...and0x3d93..., attacker swaps stolen USDT through pair0x16b9...and unwraps WBNB to native BNB. - For
0x0d9e..., measured native delta for0xd25f...is+94047881930522033994wei net of gas.
Stage C - Repetition
- The same bypass pattern is executed independently by different attacker-controlled accounts/contracts, confirming repeatable permissionless exploitability.
6. Impact & Losses
- Total observed drain:
179747.629375USDT. - Impact type: unauthorized depletion of victim pool accounting and transfer of pool-held USDT to attacker-controlled addresses.
- Affected component: victim pool proxy/implementation withdrawal path (
poolWithdraw).
7. References
- Root cause source:
root_cause.json. - Key exploit transactions:
0x0d9e4478567aa33dad3bd7c9a79de5f2afc9c7037c026795aa838f5ab834ca800x3d936c59c9d446ee222361acc820be47054aea45f9f5fc92482fe973a596e4750x91f4526052060d7137919a8e2bb3ce6c2169e5a376ab002c4745f69841cfd784
- Evidence artifacts (human-labeled):
- BSC pre-state and simulation checks (
requiredSignatures, whitelist/signer status, empty-array simulation outcomes). - Full call traces for the three exploit transactions.
- Transaction receipts with
PoolWithdrawand transfer logs. - State/balance-diff snapshots showing victim depletion and attacker gain.
- BSC pre-state and simulation checks (