ShadowFi Public Burn Drains WBNB Pair
Exploit Transactions
0xe30dc75253eecec3377e03c532aa41bae1c26909bc8618f21fb83d4330a01018Victim Addresses
0x10bc28d2810dd462e16facff18f78783e859351bBSC0xf9e3151e813cd6729d52d9a0c3ee69f22cce650aBSCLoss Breakdown
Similar Incidents
ZS Pair Burn Drain
45%CS Pair Balance Burn Drain
42%Public Mint Drains USDT Pair
41%BBOX Pair Burn Price Manipulation
40%UN Burn-Skim Exploit
39%STOToken Sell-Hook Reserve Manipulation Drains the STO/WBNB Pancake Pair
39%Root Cause Analysis
ShadowFi Public Burn Drains WBNB Pair
1. Incident Overview TL;DR
On BSC block 20969096, transaction 0xe30dc75253eecec3377e03c532aa41bae1c26909bc8618f21fb83d4330a01018 exploited the ShadowFi token and the ShadowFi/WBNB Pancake pair in a single transaction. The adversary bought a small amount of ShadowFi, burned almost the entire ShadowFi balance held by the pair through a public burn function, called sync() so the pair reserve dropped to one token unit, and then sold the acquired ShadowFi back into the manipulated pool. The sequence drained 1078616699290110670619 WBNB from the pair.
The root cause is a direct authorization failure in ShadowFi. Its public burn(address,uint256) function accepts an arbitrary account and forwards that address into _transferFrom without checking caller ownership or allowance, so any external caller can destroy tokens held by the pair.
2. Key Background
PancakeSwap V2 pairs price assets from stored reserves. If a token balance inside the pair changes for any reason, sync() updates the recorded reserves to match the current balances. An attacker who can reduce one side of the pair without paying the counter-asset can force a severe price distortion and extract the other reserve.
ShadowFi is a fee-on-transfer token, but the fee logic does not protect balances from unauthorized destruction. The relevant public contracts are the ShadowFi token at 0x10bc28d2810dd462e16facff18f78783e859351b, the ShadowFi/WBNB Pancake pair at 0xf9e3151e813cd6729d52d9a0c3ee69f22cce650a, and WBNB at 0xbb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c.
3. Vulnerability Analysis & Root Cause Summary
This incident is an ATTACK, not a benign market dislocation. The violated invariant is simple: only a holder or an approved spender should be able to reduce that holder's token balance. ShadowFi breaks that invariant by exposing a public burn entrypoint that debits any supplied address.
The verified source contains the precise breakpoint:
function burn(address account, uint256 _amount) public {
_transferFrom(account, DEAD, _amount);
emit burnTokens(account, _amount);
}
function _transferFrom(address sender, address recipient, uint256 amount) internal returns (bool) {
_balances[sender] = _balances[sender].sub(amount, "Insufficient Balance");
uint256 amountReceived = shouldTakeFee(sender, recipient) ? takeFee(sender, recipient, amount) : amount;
_balances[recipient] = _balances[recipient].add(amountReceived);
emit Transfer(sender, recipient, amountReceived);
return true;
}
Because _transferFrom authenticates neither sender nor caller intent in the burn path, any user can burn the pair's ShadowFi inventory. Once the pair is reduced to one token unit and sync() is called, the pair records an extreme reserve imbalance, making the remaining attacker-held ShadowFi redeem for nearly all WBNB in the pool.
4. Detailed Root Cause Analysis
The ACT opportunity exists at pre-state block 20969095, immediately before the adversary transaction is mined. At that point the pair still holds approximately 10354946297404462 ShadowFi and 1078615699417903036883 WBNB, and the public burn function is live. Those conditions are sufficient for an unprivileged actor to reproduce the exploit.
The seed trace shows the full exploit sequence. First, the transient helper wraps 0.001 BNB into WBNB, transfers it to the pair, and buys ShadowFi:
emit Transfer(from: PancakePair, to: 0x6ED2175Bc502f45499d233ea47e1201C1aD537de, value: 9001636470)
emit Swap(sender: 0x6ED2175Bc502f45499d233ea47e1201C1aD537de, amount0In: 0, amount1In: 1000000000000000, amount0Out: 9576209010, amount1Out: 0, to: 0x6ED2175Bc502f45499d233ea47e1201C1aD537de)
Next comes the authorization failure in action:
ShadowFi::burn(PancakePair, 10354936721195451)
emit Transfer(from: PancakePair, to: 0x000000000000000000000000000000000000dEaD, value: 10354936721195451)
The balance diff confirms the resulting state changes:
{
"pair_shadowfi_before": "10354946297404462",
"pair_shadowfi_after": "8461538283",
"pair_shadowfi_delta": "-10354937835866179",
"dead_shadowfi_delta": "10354936721195451",
"token_fee_delta": "1114670728"
}
After the burn, the helper calls sync(). The trace records the manipulated reserve state directly:
emit Sync(reserve0: 1, reserve1: 1078616699417903036883)
That is the economic pivot. The pair now treats one ShadowFi unit as the entire token-side reserve. The helper then transfers back the bought ShadowFi, swaps it against the distorted pool, and the pair pays WBNB directly to the adversary EOA:
WBNB::transfer(0x4daa3135B016Ac37C46ED03423D314CAeA89ff5e, 1078616699290110670619)
emit Swap(sender: 0x6ED2175Bc502f45499d233ea47e1201C1aD537de, amount0In: 8461538282, amount1Out: 1078616699290110670619, to: 0x4daa3135B016Ac37C46ED03423D314CAeA89ff5e)
The mechanism is deterministic and permissionless. It requires only public BSC state, the public ShadowFi burn function, the public Pancake pair, and minimal initial capital for the first buy.
5. Adversary Flow Analysis
The adversary cluster consists of EOA 0x4daa3135b016ac37c46ed03423d314caea89ff5e and transient helper contract 0x6ed2175bc502f45499d233ea47e1201c1ad537de. The helper performs the exploit steps and routes proceeds back to the EOA.
The on-chain execution flow is:
- Deposit
0.001BNB into WBNB. - Transfer WBNB to the pair and buy ShadowFi.
- Read the pair's remaining ShadowFi balance and call
burn(pair, pairBalance - 1). - Call
sync()so the pair reserves become1ShadowFi versus1078616699417903036883WBNB. - Transfer the attacker-held ShadowFi back to the pair and swap it out for WBNB.
- Receive
1078616699290110670619WBNB at the EOA.
The final pair WBNB balance is only 127792366264 wei, so the pool is effectively emptied.
6. Impact & Losses
The measurable loss is:
WBNB:1078616699290110670619raw units with18decimals
The ShadowFi/WBNB pair lost essentially its entire WBNB inventory. Liquidity providers absorb the loss, while the attacker realizes the drained WBNB in one transaction.
7. References
- Seed transaction trace for
0xe30dc75253eecec3377e03c532aa41bae1c26909bc8618f21fb83d4330a01018 - Seed transaction metadata for sender, gas usage, and constructor input
- Seed balance diff for pair, dead-address, and fee-account deltas
- Verified ShadowFi source at
0x10bc28d2810dd462e16facff18f78783e859351b - ShadowFi/WBNB Pancake pair at
0xf9e3151e813cd6729d52d9a0c3ee69f22cce650a