BNB Chain
Reserve manipulation

XPlayer's $965K Loss and How Olympix Would Have Prevented It

Loss
Loss
Exploit date
January 28, 2026

Date: January 28, 2026

Chain: BNB Chain

Loss: 964,588 USDT drained from the XPL/USDT PancakeSwap pair, of which 718,844 USDT ended up as the attacker's profit

Class: a burn schedule anyone could trigger that removed tokens straight from the liquidity pair

On January 14, 2026, X Player pinned a post announcing the contract address of XPL, its platform token on BNB Chain, and inviting users to look forward to the project's future. Fourteen days later, at 13:33:47 UTC on January 28, a single transaction took 964,588 USDT out of XPL's PancakeSwap liquidity pool, and the attacker's wallet walked away with 718,844 USDT after paying back roughly 239.5M USDT in flash loans.

The attacker didn't need to find a way into the pool's reserves. XPL already shipped with one: a function called DynamicBurnPool that destroys XPL sitting inside the liquidity pair and then tells the pair to re-read its balances. It was meant for a scheduled daily burn run by trusted contracts, and according to BlockSec, the scheduler in front of it let anyone fire that burn once the day's target was set. Burning XPL out of the pool while the pool held almost none of it made the last few XPL in the pair worth almost every USDT the pool had.

A Token That Burned Its Own Pool

XPL was deployed on January 14, 2026, at 00:56 UTC, and paired with USDT on PancakeSwap V2. A PancakeSwap V2 pair prices its two tokens by the ratio of its reserves, the constant-product rule. Every swap has to leave the product of the two reserves at least as large as before, which is what stops anyone from taking value out without putting value in. The rule only holds if the reserves change through swaps, deposits and withdrawals. A token contract that removes its own tokens from the pair and then calls sync() changes one reserve with nothing coming back in on the other side.

XPL was built to do exactly that, on purpose. Its token contract includes an automatic burn that takes a slice of the pair's XPL every interval and a manual one, DynamicBurnPool, for burns run by the project's own contracts. From the XPL source verified on Sourcify, in XPLBase.sol:

function DynamicBurnPool(uint256 _amount) public {
    require(
        msg.sender == owner() ||
            msg.sender == staking ||
            msg.sender == address(nodeShareAddress) ||
            msg.sender == address(marketingAddress),
        "k012"
    );
    if (_shouldFee()) {
        super._update(address(uniswapV2Pair), DEAD_ADDRESS, _amount);
        uniswapV2Pair.sync();
        emit AutoEvent("_autoBurnPoolByOwner", block.timestamp);
    }
}

The require accepts four callers, the owner, the staking contract, the node distribution contract stored in nodeShareAddress, and the marketing address. If the token's total burned supply hasn't hit its floor, which is what _shouldFee() checks, the function moves _amount of XPL from the pair straight to the dead address using the parent ERC-20's internal _update, skipping every fee and limit in XPL's own transfer logic. It then calls sync() so the pair adopts its new, smaller XPL balance as its reserve. Nothing in the function bounds _amount against the pair's balance, and nothing ties the burn to a price or a time. Every protection rests on the four callers.

The Gate Opened From the Other Side

One of those callers, nodeShareAddress, pointed to a contract called NodeDistributePlus, which sits behind an upgradeable proxy at 0xb413. According to BlockSec's weekly incident roundup, it ran XPL's daily burn schedule. A privileged account set the day's burn target, and then anyone could call NodeDistributePlus's own DynamicBurnPool during a two-day window until that target was reached. NodeDistributePlus would then call XPL's DynamicBurnPool as an authorized caller.

That made the four-caller check in the token meaningless for burns. XPL trusted NodeDistributePlus, and NodeDistributePlus passed that trust to whoever called it. The implementation that the NodeDistributePlus proxy points to today, verified on Sourcify, requires a whitelisted caller before it forwards a burn, which is the guard that matters. A permission check only protects a function if every contract allowed through it applies the same check to its own callers, and a check that stops one hop short protects nothing.

One Transaction on January 28

The attacker's wallet at 0x9df9 called its attack contract at 0x80bd in block 77915282. According to BlockSec, the contract gathered about 239.5M USDT in flash loans and borrowed liquidity from several lenders, and the transaction's token transfers show USDT arriving from nine separate sources before the contract touched XPL.

BlockSec describes the sequence. The attack contract bought about 69 XPL for 100 USDT, then bought about 691,000 XPL with roughly 217.1M USDT, which left the pair holding a large USDT reserve against very little XPL. The 691,022 XPL from that second purchase went to XPL's marketing address, according to the transaction's logs. The contract then triggered the scheduled burn, and the transaction's logs show 3,078 XPL moving from the pair to the dead address followed by a sync. With the pair's XPL reserve cut to almost nothing, the contract sold back its first 69 XPL, and the pair paid out 218,083,490 USDT for them.

Across the whole transaction the pair took in 217,118,902 USDT and paid out 218,083,490 USDT, a net loss of 964,588 USDT to XPL's liquidity providers. About 245,744 USDT of that went to the lenders as flash-loan fees, and the contract sent the remaining 718,844 USDT to the attacker's wallet. That profit is the roughly $717K figure in BlockSec's report and CertiK's alert, while EGW News cites community analysts who put the loss at up to 964,600 USDT, which matches the pair's on-chain outflow.

CertiK's monitoring flagged the attack, and EGW News reports that CertiK compared it with the PGNLZ exploit a day earlier on BNB Chain, which drained about $100K through a similar burn-from-pair mechanism. As of October 23, 2026, the X Player account's pinned post still announces the XPL contract, and none of the published analyses cite a post-mortem from the team.

How Olympix Follows a Trusted Caller to the Function Behind It

Olympix reads a contract the way an attacker does, as states, transitions and entry points, and it takes in the context around the code, here the PancakeSwap pair XPL trades against and the contracts it trusts, to infer the invariants the system depends on. In XPL, the state that matters is the pair's reserves, and every path that can change a reserve without a swap is a path worth mapping, whether it starts in the token or in a contract the token trusts.

Olympix's static analysis surfaces the signal: a function that moves tokens out of the AMM pair and calls sync(), reachable from an external entry point whose only gate is a list of trusted contract addresses, one of which exposes a public function that forwards the call. Olympix has flagged this class before in other codebases, a role check that holds in one contract and leaks through another. From that signal, the engine narrows from every path, to the feasible ones that reach DynamicBurnPool, to the ones an unprivileged account can start, which is where the invariant breaks.

The invariant is one sentence: no address outside the project's own operators should be able to reduce the pair's XPL reserve without trading for it. BugPoCer goes after that rule with Counterexample-Guided Invariant Refutation, working outward from the token and the contracts it trusts, inferring the rule from how the burn functions are gated, and executing paths from an ordinary account until one shrinks the reserve. Symbolic execution supports that search by solving for the call sequence and timing that open the burn window, an engine component BugScout also relies on when it attacks the same path from the signal inward with known AMM manipulation strategies.

The counterexample for this exploit would show an unprivileged account calling NodeDistributePlus inside an open burn window, XPL's DynamicBurnPool executing as if a trusted contract had decided to burn, the pair's XPL reserve dropping with no USDT leaving or entering, and a sale of a small amount of XPL that returns far more USDT than the seller paid. It would state the minimal conditions, a daily target set and a caller nobody vetted, and it would come with a generated Forge test that replays the sequence on a fork and asserts that the pair's USDT reserve fell while the caller's balance rose. That's the January 28 drain produced in development instead of on BNB Chain.

Because Olympix runs automatically in development, at every merge and before release, the check would have run on the commit that made NodeDistributePlus's burn callable by anyone and again before XPL went live on January 14, with the token and its scheduler analyzed together as one system.

Trust Has to Travel With the Check

XPL's token contract checked its callers, and NodeDistributePlus enforced a daily target and a two-day window, and the pool still lost 964,588 USDT because the caller check stopped one contract short of the person actually calling. For builders, any function that can change an AMM reserve without a trade deserves to be treated as the most sensitive function in the codebase, with its access traced all the way back to the outermost caller. To see how Olympix follows every trusted address in your contracts to the public function behind it and returns a runnable counterexample where the trust leaks, book a technical walkthrough.

On-Chain References

Protocol: X Player (XPL token)

Chain: BNB Chain

Date: January 28, 2026, 13:33:47 UTC

Loss: 964,588 USDT net outflow from the XPL/USDT pair (718,844 USDT attacker profit)

Attacker EOA: 0x9df9...094f

Attack contract: 0x80bd...9bd9

Exploit tx: 0x9779...2e49

Block: 77915282

XPL token: 0xC2c4...20b8

XPL deployment tx: 0x7f0a...5762

XPL/USDT PancakeSwap pair: 0x9b0f...ce70

NodeDistributePlus proxy (nodeShareAddress): 0xb413...7854

XPL marketing address: 0x4073...d0ae

Sources

BlockSec: Weekly Web3 Security Incident Roundup, Jan 25 to Feb 1, 2026

EGW News: X Player Hit with $717K Attack Similar to PGNLZ

Sourcify: Verified XPL token source (exact match)

See what Olympix finds on your own code

Send us a repo that's already been audited, and we'll run Olympix at the same commit and show you what comes back.