Utopia Reserve Overwrite Drain
Exploit Transactions
0xeb4eb487f58d39c05778fed30cd001b986d3c52279e44f46b2de2773e7ee1d5eVictim Addresses
0xb1da08c472567eb0ec19639b1822f578d39f3333BSC0xfeef619a56fce9d003e20bf61393d18f62b0b2d5BSCLoss Breakdown
Similar Incidents
GoldCoin Pair Reserve Overwrite
46%CoinToken Burn Reserve Drain
40%Movie Token Reserve-Burn Drain
38%Sheep Burn Reserve Drain
36%CFC Reserve Collapse
35%STOToken Sell-Hook Reserve Manipulation Drains the STO/WBNB Pancake Pair
34%Root Cause Analysis
Utopia Reserve Overwrite Drain
1. Incident Overview TL;DR
On BSC block 30119397, transaction 0xeb4eb487f58d39c05778fed30cd001b986d3c52279e44f46b2de2773e7ee1d5e used a freshly deployed attacker helper contract to manipulate the Utopia/WBNB Pancake pair at 0xfeef619a56fce9d003e20bf61393d18f62b0b2d5 and extract 492088605739133158123 wei of WBNB. The attack was permissionless: the attacker only needed public pair functions, public token state, and normal swap access.
The root cause is in Utopia token contract 0xb1da08c472567eb0ec19639b1822f578d39f3333. During non-whitelisted pair transfers, _transfer calls _airdrop, and _airdrop overwrites the computed address balance with 1 instead of preserving existing balances. By steering that computed address to the Pancake pair itself, the attacker forces the pair token balance to 0, then back to 1, and finally exploits Pancake reserve-based pricing to drain nearly all WBNB liquidity.
2. Key Background
Three protocol behaviors matter for this incident.
First, Pancake pairs trust live ERC-20 balances when sync() updates reserves. If a token contract reports a manipulated balanceOf(pair), Pancake records that manipulated value as the pair reserve.
Second, skim(to) transfers any token amount above the currently stored reserve to to. Pancake does not validate whether the token contract maintains sane internal bookkeeping for unrelated accounts.
Third, Utopia injects extra balance mutation into pair transfers. The verified source shows that on non-whitelisted transfers involving a swap pair, _transfer calls _airdrop(from, to, amount) before _tokenTransfer settles the actual transfer:
if (!_feeWhiteList[from] && !_feeWhiteList[to]) {
takeFee = true;
...
_airdrop(from, to, amount);
}
_tokenTransfer(from, to, amount, takeFee, isAddLP);
That extra hook is what makes the pair balance externally forgeable.
3. Vulnerability Analysis & Root Cause Summary
This is an ATTACK-class bug in the token’s accounting, not a benign MEV opportunity. The safety invariant is straightforward: a token transfer must only update balances that correspond to the actual transfer or fee logic, and it must not overwrite arbitrary third-party balances. Utopia breaks that invariant in _airdrop.
The relevant code is:
function _airdrop(address from, address to, uint256 tAmount) private {
uint256 seed = (uint160(lastAirdropAddress) | block.number) ^ (uint160(from) ^ uint160(to));
address airdropAddress;
uint256 airdropAmount = 1;
...
airdropAddress = address(uint160(seed | tAmount));
_balances[airdropAddress] = airdropAmount;
...
lastAirdropAddress = airdropAddress;
}
The breakpoint is the assignment _balances[airdropAddress] = 1. It does not mint, increment, or conserve supply. It simply overwrites the chosen account balance slot with 1. Because airdropAddress depends on attacker-influenced inputs (lastAirdropAddress, block.number, from, to, tAmount), the attacker can steer this overwrite into the Pancake pair balance slot.
4. Detailed Root Cause Analysis
The exploit starts from BSC state immediately before block 30119397, when the Utopia/WBNB pair still held a large Utopia reserve and 507504915442740086636 wei of WBNB. The attacker EOA 0xe84ef3615b8df94c52e5b6ef21acbf0039b29113 deployed helper contract 0x6191203510c2a6442faecdb6c7bb837a76f02d23 and used it as the adversary execution surface.
The trace first shows a buy into Utopia, giving the helper enough Utopia to manipulate pair state. The critical reserve-poisoning phase then happens in four steps:
- The helper transfers
1wei of Utopia into the pair, which updateslastAirdropAddress. - The helper reads
lastAirdropAddress()and computes askimrecipient whose address bits cause the next_airdropcall to resolve to the pair address. - During
PancakePair::skim(recipient), the pair transfers1wei of Utopia out. Inside Utopia,_airdropoverwrites_balances[pair] = 1, and then the real transfer subtracts1, leaving the pair balance at0. sync()records reserve0 as0. The helper then sends another1wei of Utopia to the pair and callssync()again, making reserve0 exactly1.
The decisive trace segment is:
PancakePair::skim(0xfF2651b286694eD2Fd2fC8907f57dd0Ae9FFF5Fd)
Utopia::transfer(..., 1)
...
PancakePair::sync()
Utopia::balanceOf(pair) -> 0
emit Sync(reserve0: 0, reserve1: 507504915442740086636)
...
Utopia::transfer(pair, 1)
PancakePair::sync()
Utopia::balanceOf(pair) -> 1
emit Sync(reserve0: 1, reserve1: 507504915442740086636)
At that point the pair advertises reserves of (1 Utopia, 507504915442740086636 WBNB). The attacker then transfers 32 wei of Utopia in and uses Pancake’s quote logic against the falsified reserve ratio:
getAmountOut(32, 1, 507504915442740086636) -> 492088605739133158123
PancakePair::swap(0, 492088605739133158123, attackerHelper, 0x)
The pair pays out 492088605739133158123 wei of WBNB, leaving only 15416309703606928513 wei of WBNB and 33 wei of Utopia in the pool. The balance-diff artifact independently confirms the pair’s Utopia balance collapsing from 1768838349283261391642 to 33, while the attacker helper ends with the drained WBNB.
5. Adversary Flow Analysis
The adversary flow is fully contained in the single transaction 0xeb4eb487f58d39c05778fed30cd001b986d3c52279e44f46b2de2773e7ee1d5e.
EOA 0xe84ef361... sends 0.1 BNB
-> deploy helper 0x6191203510...
-> wrap BNB to WBNB
-> buy Utopia through Pancake router
-> transfer 1 wei Utopia to pair
-> read lastAirdropAddress()
-> skim(craftedRecipient)
-> sync() // reserve0 becomes 0
-> transfer 1 wei Utopia to pair
-> sync() // reserve0 becomes 1
-> transfer 32 wei Utopia to pair
-> swap out 492.088605739133158123 WBNB
The attacker-related accounts are deterministic and evidenced by metadata plus trace:
- EOA
0xe84ef3615b8df94c52e5b6ef21acbf0039b29113funded and submitted the exploit transaction. - Contract
0x6191203510c2a6442faecdb6c7bb837a76f02d23was created inside that transaction, executed the exploit calls, and retained the WBNB proceeds.
No privileged role, private key compromise, or hidden dependency is required. The exploit only relies on public state inspection and public calls to transfer, skim, sync, and swap.
6. Impact & Losses
The victimized liquidity pool is the Utopia/WBNB Pancake pair at 0xfeef619a56fce9d003e20bf61393d18f62b0b2d5. The incident drained:
492088605739133158123wei ofWBNB(492.088605739133158123 WBNB)
After the swap, the pair was left with only 15416309703606928513 wei of WBNB and 33 wei of Utopia. Economically, the exploit converted an almost fully depleted counterasset reserve into attacker profit by first corrupting the pair’s observed Utopia reserve.
7. References
- Exploit transaction metadata:
0xeb4eb487f58d39c05778fed30cd001b986d3c52279e44f46b2de2773e7ee1d5e - Full execution trace for that transaction, showing
skim,sync,getAmountOut, andswap - Balance-diff artifact for the same transaction, confirming the pair depletion and attacker profit
- Verified Utopia source for
0xb1da08c472567eb0ec19639b1822f578d39f3333, especially_transferand_airdrop