All incidents

STOToken Sell-Hook Reserve Manipulation Drains the STO/WBNB Pancake Pair

Share
Feb 20, 2026 04:29 UTCAttackLoss: 118 WBNBManually checked1 exploit txWindow: Atomic
Estimated Impact
118 WBNB
Label
Attack
Exploit Tx
1
Addresses
2
Attack Window
Atomic
Feb 20, 2026 04:29 UTC → Feb 20, 2026 04:29 UTC

Exploit Transactions

TX 1BSC
0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03
Feb 20, 2026 04:29 UTCExplorer

Victim Addresses

0xc6941c6bffdc844073e2c7c22816216c3890cd65BSC
0xa4e56ac9aa21184a0f68e2963b51146a4f556495BSC

Loss Breakdown

118WBNB

Similar Incidents

Root Cause Analysis

STOToken Sell-Hook Reserve Manipulation Drains the STO/WBNB Pancake Pair

1. Incident Overview TL;DR

At 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.

2. Key Background

  • Pair model: Pancake V2 pricing/invariant checks assume reserves are updated from canonical token-in/token-out flow.
  • Victim token behavior: STOToken::_update includes custom buy/sell logic and a pre-sell burn hook.
  • ACT framing: no privileged role is required; any unprivileged actor can route swaps against public liquidity if sell path is open.

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.

3. Vulnerability Analysis & Root Cause Summary

The issue is an ATTACK-class logic flaw at the token/AMM integration boundary. In the sell branch, STOToken computes a sellAmount, then executes _burn(lpPair, burnFromPair) and IUniswapV2Pair(lpPair).sync() before super._update(from, to, sellAmount). 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.

Invariant violated:

  • During swap-critical execution, pair reserves should not be externally rewritten by token hooks beyond canonical transfer accounting.

Code-level breakpoint:

  • STOToken::_update sell path executes _burn(lpPair, burnFromPair); sync(); before seller transfer completion.

4. Detailed Root Cause Analysis

  1. The incident transaction is replayable from public pre-state (metadata, trace, and verified token source are available).
  2. The adversary performs a buy leg to load WBNB into the pair and prepare for the sell-triggered hook.
  3. On the sell leg (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);
  1. Trace evidence shows reserve manipulation before payout:
emit Transfer(from: PancakePair, to: 0x000..., amount: 1355905591116876893542)
PancakePair::sync()
emit Sync(reserve0: 682394686810760079681353, reserve1: 9)
emit PreSellBurn(amountBurned: 1355905591116876893542)
  1. The pair then pays out WBNB using the manipulated reserve context:
PancakePair::swap(682394686810760079676812, 0, attacker, 0x)
WBNB::transfer(attacker, 682394686810760079676812)
emit Sync(reserve0: 4541, reserve1: 1355905591116876893551)
  1. Final state confirms severe quote-side depletion (reserve0 = 4541) and successful extraction.

Exploit conditions:

  • isSellOpen == true.
  • Pair has non-zero STO so burnFromPair > 0 can execute.
  • Public router access (no privileged permissions).

5. Adversary Flow Analysis

Adversary cluster:

  • 0x87a8ff8ad993c10af4ad85b62ddb50b4968abc93 (EOA sender and payout beneficiary in incident tx).

Victim components:

  • STOToken: 0xc6941c6bffdc844073e2c7c22816216c3890cd65
  • PancakePair(STO/WBNB): 0xa4e56ac9aa21184a0f68e2963b51146a4f556495
  • PancakeRouterV2: 0x10ed43c718714eb63d5aa57b78b54704e256024e

End-to-end sequence inside tx 0xf7f741...22e03:

  1. Buy leg: swapExactTokensForTokensSupportingFeeOnTransferTokens on path [WBNB, STO], outputting 7820156662440489446414626 STO.
  2. Sell trigger: STO transfer to pair executes burn+sync hook and emits PreSellBurn.
  3. Extraction: pair swap pays 682394686810760079676812 WBNB; pair WBNB reserve collapses to 4541.

6. Impact & Losses

Measured impact in incident tx:

  • Gross round-trip extraction in WBNB terms: 118001474297520951667 wei.
  • Native gas cost observed: 574744117500000 wei BNB.
  • Pool health impact: WBNB reserve of STO/WBNB pair drops to near-zero (4541), representing immediate liquidity depletion.

7. References

  • Incident tx metadata: /workspace/session/artifacts/collector/seed/56/0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03/metadata.json
  • Incident full trace: /workspace/session/artifacts/collector/seed/56/0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03/trace.cast.log
  • Balance deltas: /workspace/session/artifacts/collector/seed/56/0xf7f741bf17299050a6e068f0af6eabc22f6389301d18b3c610537d7cc4422e03/balance_diff.json
  • STOToken source (breakpoint): /workspace/session/artifacts/collector/seed/56/0xc6941c6bffdc844073e2c7c22816216c3890cd65/src/STOTOKEN.sol