Crypto exploits

FHToken exploit analysis

On 2026-08-25, an attacker on BNB Chain drained FHToken's FH/USDT pair of ~19,999.02 USDT over 25 buy/sell cycles by exploiting a sell-tax reserve mismatch and a premature `pair.sync()`.

Reported loss
19,999.018106552928530404 USDT (~$20K), per DeFiHackLabs
Occurred
Logged

Logged as “2026-08-25: Sell Tax Reserve Mismatch Via Premature Sync on FHToken”.

Analysis1 min read

FHToken's _transfer treats a transfer whose recipient is the FH/USDT PancakeSwap pair as a "sell". On a sell, the contract does not tax the seller's amount into the pool. Instead it burns 80 percent and moves 20 percent of the net amount out of the pool's own FH balance, then calls pair.sync() BEFORE crediting the seller's net FH to the pair. sync() latches the pool's FH reserve to the post-burn but pre-credit balance, which is far below the pair's true post-transfer FH balance. PancakeSwap's getAmountOut then values the sell against the shrunken FH reserve and overpays USDT.

The sell path is triggered automatically inside _transfer for any transfer into the pair, with only tradingEnabled and a blacklist check. The buy path is gated (the recipient must be in isBuyerWhitelist), so the attacker routed the buy leg's output through a hardcoded-whitelisted SwapRouter (the 0x1b81D678 router, whitelisted in FHToken's constructor) and then pulled the FH back with that router's public sweepToken(). Each buy first inflates the pool's USDT side, so the following sell's overpay compounds; looping 25 buy/sell cycles drains it.

The attacker ran the exploit in a single transaction on block 117979402 of BNB Chain (0x7a3cadc2f33e000b0091307df62db2f5cc79ab8e0b022fd84de9e1c2c0745bd2), funded by a fee-free flash loan from the Moolah lending pool. Net profit was ~19,999.0181 USDT.

The PoC reconstructs the attack with typed calls to the real PancakeSwap V2 router at 0x10ED43C718714eb63d5aA57B78B54704E256024E and the real 0x1b81D678 router, taking a real onMoolahFlashLoan callback from the same Moolah pool. Moolah's flash loan uses transient storage, so the PoC runs on the cancun EVM version. Only the per-cycle USDT buy sizes are taken from the original transaction, so the pool follows the same trajectory; every swap is executed by the real contracts on the fork.

The fix is to call pair.sync() AFTER the seller's net FH has been credited to the pair, not before, or to skip the privileged burn and treasury split on the sell path entirely. The deeper fix is to never let a token contract's _transfer invoke pair.sync() itself: that responsibility belongs to the pair.

Sources read (3)

Other exploits

Query every incident yourself — free, no signup

Updated 14 Oct 2026. Figures are as reported by the sources listed above and are not independently verified.