SellToken Short Oracle Manipulation
Exploit Transactions
0x7d04e953dad4c880ad72b655a9f56bc5638bf4908213ee9e74360e56fa8d7c6a0xd877c0c2852ee688706a3899e7233a32c57ecef7616afe97b74aaff1b58964bd0xca4e97a3221026c4fd271a342e7ff21ab4006e15da7b3801e8c44d66780fe8d60x893453b1c9db19d59548bf05c9213e1d2a9ff8195c4f0bc5f17bba9b3b18beeeVictim Addresses
0x57Db19127617B77c8abd9420b5a35502b59870D6BSC0x8D190C70937493046a464440d28f126A4E42eF7fBSCLoss Breakdown
Similar Incidents
SellToken Arbitrary-Pair LP Drain
45%WILL/USDT expired short overfunding exploit
38%NovaX TokenStake Oracle Manipulation Exploit
38%Local Traders Price Takeover
35%QiQi Reward Quote Override Drain
33%STOToken Sell-Hook Reserve Manipulation Drains the STO/WBNB Pancake Pair
33%Root Cause Analysis
SellToken Short Oracle Manipulation
1. Incident Overview TL;DR
SellToken on BNB Smart Chain exposed an ACT-style short-engine exploit because it let any user list arbitrary tokens through its Minerals child and then priced both short entry and short settlement from live PancakeSwap spot quotes. In seed transaction 0x7d04e953dad4c880ad72b655a9f56bc5638bf4908213ee9e74360e56fa8d7c6a at block 28168035, the attacker EOA 0x1581262Fd72776bA5DA2337C4C4E1B92C6e36ae6 used orchestrator contract 0x19Ed7Cd5F1d2bD02713131344d6890454D7C599F to borrow WBNB from public DODO pools, manipulate the 0xa645995e9801F2ca6e2361eDF4c2A138362BADe4/WBNB Pancake market, open a short against the inflated quote, reverse the market, and settle against the depressed quote.
The root cause is the combination of two permissionless design choices in protocol contract 0x57Db19127617B77c8abd9420b5a35502b59870D6 and its Minerals child 0x8D190C70937493046a464440d28f126A4E42eF7f: anyone can seed and register an arbitrary token market, and the protocol trusts attacker-controllable IRouter.getAmountsOut spot prices in both setTokenPrice / ShortStart and withdraw. The seed balance diff shows the attacker EOA's native balance increased from 239.449728247930520710 BNB to 274.705384655194683681 BNB, a net gain of 35.255656407264162971 BNB after gas.
2. Key Background
SellToken is a short engine that deploys and uses a Minerals child contract to hold token inventory and route Pancake trades. The verified protocol source shows:
Minerals.setPool(..., isPool = 1)accepts arbitrary token listings as long as the paired asset is WBNB or USDT, the caller transfers tokens in, and the caller pays the listing fee.SellToken.setTokenPricestores a one-token snapshot for the caller and token, but the snapshot is just the current PancakegetAmountsOutquote and expires after 30 seconds.SellToken.ShortStartrequires that the current quote stay within 5% of the stored snapshot, but once that timer passes it again reads Pancake spot pricing to set short state and then instructsMineralsto buy more of the same token.SellToken.withdrawrecomputes payout from another spot read and hasMineralssell protocol inventory into the same market.
Independent RPC reads at block 28168034, the state immediately before the seed exploit transaction, confirm the protocol conditions claimed in root_cause.json:
SellToken.mkt() = 0x8D190C70937493046a464440d28f126A4E42eF7f
Minerals.getPair(0xa645995e9801F2ca6e2361eDF4c2A138362BADe4) = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
SellToken.tokenPrice(0x19Ed7Cd5F1d2bD02713131344d6890454D7C599F, 0xa645995e9801F2ca6e2361eDF4c2A138362BADe4) = 154467646217615
SellToken.tokenPriceTime(0x19Ed7Cd5F1d2bD02713131344d6890454D7C599F, 0xa645995e9801F2ca6e2361eDF4c2A138362BADe4) = 1683961924
Minerals.balanceOf(0xa645995e9801F2ca6e2361eDF4c2A138362BADe4) = 15917150134720644674378854
Those values show that the attacker-controlled market was already registered, the attacker contract already held a live price snapshot, the 30-second gate had already matured before block timestamp 1683961936, and the protocol had live inventory available to monetize.
3. Vulnerability Analysis & Root Cause Summary
This is an ATTACK root cause, not a benign MEV opportunity. The protocol violates a basic safety invariant for short systems: collateral limits and settlement must not depend on same-transaction, attacker-manipulable spot quotes. Instead, SellToken takes both the opening quote and the settlement quote directly from PancakeSwap through IRouter.getAmountsOut, and Minerals allows arbitrary tokens to be listed without any liquidity-quality, oracle-source, or economic-sanity control.
The verified source makes the vulnerable control flow explicit. Minerals.setPool(..., isPool = 1) seeds inventory and binds a token to WBNB or USDT without access control. SellToken.setTokenPrice stores a live quote, ShortStart checks only a narrow 5% change bound and then snapshots a fresh spot quote into short state, and withdraw computes payout from yet another fresh spot quote before calling mkt.sell. Because the attacker controls the listed token market, those price reads are attacker inputs rather than independent measurements.
The code-level breakpoint is in ShortStart at uint newTokenValue = getTokenPrice(coin,bnbOrUsdt,bnb*98/100); and in withdraw at uint getBNB = getMyShort(...) followed by uint getTokens = getTokenPrice(...) before mkt.sell(...). Once those values are derived from manipulated reserves, the protocol converts its inventory into attacker profit.
4. Detailed Root Cause Analysis
4.1 Permissionless market creation
The verified Minerals source lets any user seed protocol inventory for a new token and bind that token to WBNB or USDT:
function setPool(address token,address token1,uint coin,uint _day,uint isPool) payable public {
require(token1 == _WBNB || token1 == _USDT);
if (isPool == 0) {
...
} else {
require(msg.value >= fee);
bool isok = IERC20(token).transferFrom(_msgSender(), address(this), coin);
require(isok);
balanceOf[token] += coin;
balanceOfLook[token] += coin;
buy(_WBNB, address(_TRDT), msg.value);
if (pair[token] == address(0)) {
pair[token] = token1;
}
}
}
There is no allowlist, oracle review, or reserve-depth requirement. That is why a worthless attacker-controlled token can become shortable protocol inventory.
4.2 Oracle trust in setTokenPrice, ShortStart, and withdraw
The same verified source shows that every critical valuation uses Pancake spot quotes:
function setTokenPrice(address _token) public {
address bnbOrUsdt = mkt.getPair(_token);
tokenPrice[_msgSender()][_token] = getToken2Price(_token, bnbOrUsdt, 1 ether);
tokenPriceTime[_msgSender()][_token] = block.timestamp + 30;
}
function ShortStart(address coin,address addr,uint terrace) payable public {
require(!getNewTokenPrice(addr,coin,bnbOrUsdt) && block.timestamp > tokenPriceTime[addr][coin]);
uint tos = getToken2Price(coin,bnbOrUsdt,mkt.balanceOf(coin)) / 10;
...
uint newTokenValue = getTokenPrice(coin,bnbOrUsdt,bnb * 98 / 100);
Short[addr][coin].tokenPrice += newTokenValue;
...
mkt.buy(bnbOrUsdt,coin,bnb * 97 / 100);
}
function withdraw(address token) public {
uint getBNB = getMyShort(token, Short[_msgSender()][token].token, Short[_msgSender()][token].bnb, Short[_msgSender()][token].tokenPrice);
uint getTokens = getTokenPrice(token, address(Short[_msgSender()][token].token), getBNB);
mkt.sell(token, Short[_msgSender()][token].token, getTokens, _msgSender());
}
getTokenPrice, getToken2Price, and getMyShort all route through IRouter.getAmountsOut, so the system never leaves the attacker-controlled AMM surface. The intended invariant should have been: short sizing and settlement must be based on manipulation-resistant pricing and must not let attacker-supplied inventory be monetized through the same pool that the attacker is actively moving. SellToken breaks that invariant at both entry and exit.
4.3 Seed-transaction execution evidence
The seed trace shows the exact exploit sequence in one transaction:
PancakeRouter::swapExactTokensForTokens(400000000000000000000, 0, [WBNB, 0xa645...], 0x19Ed..., 1683961936)
0x57Db19127617B77c8abd9420b5a35502b59870D6::ShortStart{value: 13372004912332869196}(0xa645..., 0x19Ed..., 1)
PancakeRouter::swapExactTokensForTokensSupportingFeeOnTransferTokens(4975497155509288735937836, 0, [0xa645..., WBNB], 0x19Ed..., 1683961936)
0x57Db19127617B77c8abd9420b5a35502b59870D6::withdraw(0xa645...)
0x8D190C70937493046a464440d28f126A4E42eF7f::sell(0xa645..., WBNB, 1039170532126195850016999, 0x19Ed...)
0x1581262Fd72776bA5DA2337C4C4E1B92C6e36ae6::fallback{value: 35258226638094162971}
The same trace also shows the public flash-loan capital source:
0xFeAFe253802b77456B4627F8c2306a9CeBb5d681::flashLoan(418509475390597934136, ...)
0x6098A5638d8D7e9Ed2f952d35B2b67c34EC6B476::flashLoan(519334285653568463716, ...)
0x81917eb96b397dFb1C6000d28A5bc08c0f05fC1d::flashLoan(964395284628723606213, ...)
That flow is fully permissionless and matches the ACT framing in root_cause.json: public flash liquidity, public AMM trading, public ShortStart, and public withdraw.
4.4 Why the exploit is profitable
The attacker first pumps the thin Pancake market, so ShortStart records an inflated price and also sends protocol funds into mkt.buy, which acquires more of the same token for protocol inventory. The attacker then dumps the previously acquired token bag into the pool, depressing the price before withdraw. At settlement time withdraw computes a much lower implied liability from getMyShort, converts that liability back into a token amount with another manipulated quote, and forces Minerals to sell protocol-held inventory into the pool for the attacker's benefit.
The balance diff confirms the economic effect. During the seed transaction:
{
"native_balance_deltas": [
{
"address": "0x1581262fd72776ba5da2337c4c4e1b92c6e36ae6",
"delta_wei": "35255656407264162971"
},
{
"address": "0xfffffffffffffffffffffffffffffffffffffffe",
"delta_wei": "2570230830000000"
}
],
"erc20_balance_deltas": [
{
"token": "0xa645995e9801f2ca6e2361edf4c2a138362bade4",
"holder": "0x8d190c70937493046a464440d28f126a4e42ef7f",
"delta": "-958032184516997392197103"
},
{
"token": "0xa645995e9801f2ca6e2361edf4c2a138362bade4",
"holder": "0x358efc593134f99833c66894ccecd41f550051b6",
"delta": "958032184516997392197103"
}
]
}
The attacker EOA receives 35.255656407264162971 BNB net, the miner receives 0.00257023083 BNB in gas, and the pair absorbs 958032184516997392197103 token units from protocol inventory during settlement.
5. Adversary Flow Analysis
The adversary cluster identified in the analysis is:
- EOA
0x1581262Fd72776bA5DA2337C4C4E1B92C6e36ae6, the sender and net profit recipient. - Orchestrator contract
0x19Ed7Cd5F1d2bD02713131344d6890454D7C599F, the contract that borrows WBNB, manipulates the market, interacts with SellToken, and forwards profit.
The validated lifecycle is:
- Exploit round priming. In transaction
0xe306f158cd7baa8560f7d0583fd414cdeba732fa615c303bc921e81195f02b87at block28168021, the attacker EOA sends1.8BNB to orchestrator0x19Ed.... The transaction input begins with selector0x1f9031c3, and the transaction value is1800000000000000000wei. - Pre-state setup already live. Before block
28168035, the attacker-controlled token0xa645995e9801F2ca6e2361eDF4c2A138362BADe4is already paired to WBNB inMinerals, the protocol already tracks inventory for it, and the orchestrator already has a valid storedtokenPricesnapshot that survives the 30-second gate. - Flash-loan and market pump. In seed transaction
0x7d04e953dad4c880ad72b655a9f56bc5638bf4908213ee9e74360e56fa8d7c6a, the orchestrator draws WBNB from three public DODO pools and buys the listed token on Pancake, moving reserves from10,184,880,138,888,444,750,564,378 / 417,756,004,154,629,010,646to5,209,382,983,379,156,014,626,542 / 817,756,004,154,629,010,646. - Short entry at manipulated price. The orchestrator calls
ShortStartwith13.372004912332869196BNB. SellToken accepts the position, stores the manipulatednewTokenValue, and sends97%of the margin intoMinerals.buy, which purchases even more of the attacker-controlled token for protocol inventory. - Price crash and settlement. The orchestrator sells
4,975,497,155,509,288,735,937,836token units back into Pancake, crushing the WBNB side of the pool. It then callswithdraw, which recomputes liability from the depressed quote and hasMinerals.sellunload1,039,170,532,126,195,850,016,999token units into the same pool. - Profit realization. After repaying the DODO flash loans, the orchestrator unwraps the remaining WBNB and transfers
35.258226638094162971BNB to the attacker EOA. The EOA retains35.255656407264162971BNB net of gas.
The root-cause dataset also lists additional adversary-crafted exploit rounds using the same strategy: 0xd877c0c2852ee688706a3899e7233a32c57ecef7616afe97b74aaff1b58964bd, 0xca4e97a3221026c4fd271a342e7ff21ab4006e15da7b3801e8c44d66780fe8d6, and 0x893453b1c9db19d59548bf05c9213e1d2a9ff8195c4f0bc5f17bba9b3b18beee.
6. Impact & Losses
The measurable seed-round loss captured in the analysis is:
- Token:
BNB - Raw on-chain amount:
35258226638094162971 - Decimals:
18 - Human-readable amount:
35.258226638094162971BNB transferred from the orchestrator to the attacker EOA, or35.255656407264162971BNB net at the EOA after gas
The affected public protocol components are:
- SellToken protocol contract
0x57Db19127617B77c8abd9420b5a35502b59870D6 - Minerals child
0x8D190C70937493046a464440d28f126A4E42eF7f
The exploit monetizes attacker-supplied token inventory and attacker-controlled pricing, so any thinly traded token that can be listed through setPool(..., isPool = 1) is potentially convertible into reference-asset profit under the same logic.
7. References
- Seed exploit transaction:
0x7d04e953dad4c880ad72b655a9f56bc5638bf4908213ee9e74360e56fa8d7c6a - Related funding transaction:
0xe306f158cd7baa8560f7d0583fd414cdeba732fa615c303bc921e81195f02b87 - Additional related exploit rounds from the root-cause dataset:
0xd877c0c2852ee688706a3899e7233a32c57ecef7616afe97b74aaff1b58964bd,0xca4e97a3221026c4fd271a342e7ff21ab4006e15da7b3801e8c44d66780fe8d6,0x893453b1c9db19d59548bf05c9213e1d2a9ff8195c4f0bc5f17bba9b3b18beee - Verified victim source used for validation: BscScan source for
0x57Db19127617B77c8abd9420b5a35502b59870D6 - Seed execution evidence used for validation: seed transaction trace, seed metadata, and seed balance diff in the collected artifacts
- Key public addresses:
- SellToken:
0x57Db19127617B77c8abd9420b5a35502b59870D6 - Minerals:
0x8D190C70937493046a464440d28f126A4E42eF7f - Attack token:
0xa645995e9801F2ca6e2361eDF4c2A138362BADe4 - Pancake pair:
0x358EfC593134f99833C66894cCeCD41F550051b6 - Pancake router:
0x10ED43C718714eb63d5aA57B78B54704E256024E
- SellToken: