
Date: August 15, 2026
Chain: BNB Chain
Loss: $118,700, with 112,976.12 USDT net to the attack contract per the reproduced on-chain trace
Class: bond mint priced from a manipulable spot quote and never recomputed after the contract's own swap
FoxMarket was about two weeks old when it was drained. The Olympus-style rebase and bond product on BNB Chain offered a 540-day LP bond, and its entry point, FoxLpBondsPool.stake(), worked out how much to mint by asking PancakeSwap what the FOX/USDT position was worth at that instant.
On August 15, 2026, an attacker made sure the answer was wrong, then made sure it stayed wrong. A flash loan skewed the pair's reserves before stake() read its quote, and the contract carried that inflated number through its own large USDT to FOX swap and into the treasury's minting call without ever checking it again. SlowMist recorded the loss at $118,700.
A bond product like FoxMarket's takes in assets, here FOX/USDT liquidity, and issues bonds that pay out in the protocol's own token over a vesting period. The number of FOX a staker is owed depends on what their deposit is worth, so the contract needs a price. FoxLpBondsPool.stake() took that price from a PancakeSwap spot quote, the ratio of the two tokens sitting in the pool at that moment, and stored the result in a variable called _stakeAmount.
A spot quote describes the pool as it is right now, and anyone with enough capital can change what the pool looks like right now. A flash loan lets someone borrow that capital with no collateral as long as they repay it in the same transaction, which is why a price read from pool reserves in the middle of a transaction can be a price the borrower picked.
The first defect is the timing of the read. stake() takes its PancakeSwap quote before it performs its own large USDT to FOX swap, so whatever state the attacker left the reserves in is the state the contract prices from.
The second defect is what happens after. The contract's own swap moves the reserves again, but _stakeAmount is never recomputed, and Treasury.lpBonds() mints against it without deriving anything fresh. A value computed from state is only true for the state it was computed from, and once your own code changes that state, the old value becomes a claim nobody is checking. It's like quoting a customer a trade-in price, rearranging the lot, and then writing the check from the old quote.
The two defects work in sequence: the first lets the attacker choose the number, and the second carries it unchanged all the way to the mint.
According to SlowMist's analysis, the attacker took a flash loan and used it to manipulate PancakeSwap's FOX/USDT spot pricing ahead of the contract's own swap. stake() then locked in an inflated _stakeAmount, and Treasury.lpBonds() trusted it, minted excess FOX, and transferred referral rewards to an address the attacker controlled.
Those rewards were sold back into the same FOX/USDT pair inside the same transaction, which repaid the flash loan and left the attack contract with 112,976.12 USDT, according to the reproduced trace indexed by crypto.training. The referral mechanic, built to reward users for bringing others in, became the route the excess tokens took out.
The whole sequence ran in one transaction at 23:32:59 UTC on August 15, sent by 0x5670...0ef9 to the attack contract SlowMist identifies, 0x3a82...d2da. Its logs show the scale of the borrowing: the attack contract passed 481,974,785.54 USDT through a helper contract into the FOX/USDT pair in two deposits of 240,987,392.77 USDT each, and the same transaction minted 88,659,280.81 sFOX, the protocol's staked FOX, to that helper. AMLBot later reported that the attacker's wallet had been gas-funded with 1 BNB from FixedFloat nearly two months earlier, and that about 119.14K USDT had moved through several hops and was sitting dormant at 0x0058...31e2. No public response from the team turned up in reporting on the incident, and the X account AMLBot tagged for the project, @foxmedia257236, showed as suspended on October 19, 2026.
Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it infers the rules the system depends on from the code and its context. In FoxLpBondsPool, the state that matters is the pair's reserves and the bond accounting built on them, and stake() is an entry point that both reads and changes those reserves in one call. The engine maps paths like this and uses signals to decide which to attack.
For the first defect, the signal depends on how one line of stake() asks for the price. If stake() reads the pair's reserves directly, Olympix's static analysis flags it as a price read with no staleness, deviation or round check. If it asks the router for a quote instead, that signal doesn't fire. None of the analyses cited here show which way FoxMarket wrote it, so this post doesn't claim the static catch.
The second defect doesn't depend on how the price was read, and that's the one BugPoCer is built for. It runs Counterexample-Guided Invariant Refutation over the bond pool as a whole, inferring what the mint relies on and driving stake() through every reachable reserve state until that rule fails. The rule here is that the value used to mint bonds has to come from the reserve state that exists when the mint happens. BugPoCer's counterexample is the August 15 sequence, a reserve skew before stake(), a quote taken in that state, the contract's own swap moving the reserves, and a mint against the old number, returned with the minimal conditions that trigger it and a generated Forge test that replays it. Because Olympix runs at every merge and before release, a mint path like this would be tested before any LP bond went live.
FoxMarket's loss came from a number that was correct for a moment the contract had already moved past. Any function that reads a price, changes the pool, and then pays out should price the payout from the state it actually pays in, and should treat a spot quote as something a borrower can set. If your contracts mint or reward against AMM prices, book a technical walkthrough.
Protocol: FoxMarket (FoxLpBondsPool and Treasury)
Chain: BNB Chain
Date: August 15, 2026, 23:32:59 UTC
Loss: $118,700 (112,976.12 USDT net to the attack contract)
Attacker EOA: 0x5670...0ef9
Attack contract: 0x3a82...d2da
FoxLpBondsPool: 0x58e2...655a
Treasury: 0x8761...e04d
USDT/FOX PancakeSwap pair: 0xaab1...8803
FOX token: 0xdf81...bb93
Exploit tx: 0x8e17...5514
Block: 116169049
Dormant funds (per AMLBot): 0x0058...31e2
SlowMist: FoxMarket exploit alert
SlowMist Hacked: BSC incident database (FoxMarket, 2026-08-15)