Calculated from recorded token losses using historical USD prices at the incident time.
0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e030xc6941c6bffdc844073e2c7c22816216c3890cd65BSC0xa4e56ac9aa21184a0f68e2963b51146a4f556495BSCAt BSC block 82257843, transaction 0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03 performs a two-leg route (WBNB -> STO, then STO -> WBNB) through Pancake Router and extracts value from pair 0xa4e56ac9aa21184a0f68e2963b51146a4f556495.
The root cause is in STOToken (0xc6941c6bffdc844073e2c7c22816216c3890cd65): during sell transfers to the pair, token code burns pair-held STO and calls sync() before finishing the seller transfer to the pair. That mid-swap reserve rewrite violates AMM reserve-accounting assumptions and enables outsized WBNB payout.
STOToken::_update includes custom buy/sell logic and a pre-sell burn hook.The exploitable condition is not private-key or admin dependent. It is a deterministic side effect of token transfer logic interacting with AMM reserve snapshots.
The issue is an ATTACK-class logic flaw at the token/AMM integration boundary. In the sell branch, STOToken computes a sellAmount, then executes and before . This allows the pair to record an artificially low STO reserve during swap pricing. Router/pair logic then executes against the manipulated reserve state, paying an excessive WBNB amount. Immediately after, token transfer settlement restores STO balance while quote-side liquidity has already been extracted.
_burn(lpPair, burnFromPair)IUniswapV2Pair(lpPair).sync()super._update(from, to, sellAmount)Invariant violated:
Code-level breakpoint:
STOToken::_update sell path executes _burn(lpPair, burnFromPair); sync(); before seller transfer completion.metadata, trace, and verified token source are available).to == lpPair), token logic enters the vulnerable sequence:uint256 pairBal = super.balanceOf(lpPair);
uint256 burnFromPair = sellAmount > pairBal ? pairBal : sellAmount;
if (burnFromPair > 0) {
_burn(lpPair, burnFromPair);
IUniswapV2Pair(lpPair).sync();
emit PreSellBurn(burnFromPair);
}
super._update(from, to, sellAmount);
emit Transfer(from: PancakePair, to: 0x000..., amount: 1355905591116876893542)
PancakePair::sync()
emit Sync(reserve0: 682394686810760079681353, reserve1: 9)
emit PreSellBurn(amountBurned: 1355905591116876893542)
PancakePair::swap(682394686810760079676812, 0, attacker, 0x)
WBNB::transfer(attacker, 682394686810760079676812)
emit Sync(reserve0: 4541, reserve1: 1355905591116876893551)
reserve0 = 4541) and successful extraction.Exploit conditions:
isSellOpen == true.burnFromPair > 0 can execute.Adversary cluster:
0x87a8ff8ad993c10af4ad85b62ddb50b4968abc93 (EOA sender and payout beneficiary in incident tx).Victim components:
STOToken: 0xc6941c6bffdc844073e2c7c22816216c3890cd65PancakePair(STO/WBNB): 0xa4e56ac9aa21184a0f68e2963b51146a4f556495PancakeRouterV2: 0x10ed43c718714eb63d5aa57b78b54704e256024eEnd-to-end sequence inside tx 0xf7f741...22e03:
swapExactTokensForTokensSupportingFeeOnTransferTokens on path [WBNB, STO], outputting 7820156662440489446414626 STO.PreSellBurn.682394686810760079676812 WBNB; pair WBNB reserve collapses to 4541.Measured impact in incident tx:
118001474297520951667 wei.574744117500000 wei BNB.4541), representing immediate liquidity depletion./workspace/session/artifacts/collector/seed/56/0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03/metadata.json/workspace/session/artifacts/collector/seed/56/0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03/trace.cast.log/workspace/session/artifacts/collector/seed/56/0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03/balance_diff.json/workspace/session/artifacts/collector/seed/56/0xc6941c6bffdc844073e2c7c22816216c3890cd65/src/STOTOKEN.sol