On 2026-05-07 08:14:47 UTC, the White Eagle withdrawal contract on BNB Chain was exploited through a spot-price manipulation logic flaw in its withdrawal path. The attacker used an orchestrator plus 11 helper contracts to call withdraw() repeatedly, then sold each WEGL payout into the WEGL/USDT PancakeSwap pool before the next withdrawal repriced the same USD-denominated balance into even more WEGL. The withdrawal contract lost 9888.680557825521425533 WEGL, while the profit receiver collected 65645.944170470965224333 USDT. In short, the contract converted internal USD balances into WEGL using a live AMM quote, so each same-transaction dump made subsequent withdrawals overpay in WEGL.
Root Cause
Vulnerable Contract
White Eagle withdrawal contract at 0x0079517e4157f95cefda99d295fd74fc9b9896eb on BNB Chain. It is not a proxy per the planner stage. Source type: verified at artifacts/analysis_0x538c8964c841369bee9fd52d3ad87de9202fd182caaa32acf58095d02f6b359d/0x0079517e4157f95cefda99d295fd74fc9b9896eb/weglcontract.sol.
Vulnerable Function
withdraw() (0x3ccfd60b) in weglcontract.sol, with pricing delegated to getWeglAmountFromUsd(uint256).
Vulnerable Code
function withdraw() public nonReentrant {
User storage user = users[msg.sender];
require(user.isExist, "User not exist");
uint256 roiPending = _calculatePendingROI(msg.sender);
uint256 levelPending = _calculatePendingLevelIncome(msg.sender);
uint256 uplinePending = _calculatePendingUplineIncome(msg.sender);
if (roiPending > 0) {
user.earnedFromRoi += roiPending;
_distributeRoiToInvestments(msg.sender, user);
}
if (levelPending > 0) {
user.earnedFromLevel += levelPending;
user.accumulatedLevelIncome = 0;
emit LevelIncome(msg.sender, levelPending);
}
if (uplinePending > 0) {
user.earnedFromUpline += uplinePending;
emit UplineIncome(msg.sender, uplinePending);
}
user.lastLevelWithdraw = block.timestamp;
user.lastUplineWithdraw = block.timestamp;
_creditIncome(user, roiPending + levelPending + uplinePending);
uint256 payoutUSD = user.availableWalletUSD;
require(payoutUSD > 0, "No funds");
user.availableWalletUSD = 0;
uint256 totalWegl = getWeglAmountFromUsd(payoutUSD); // <-- VULNERABILITY
require(weglToken.balanceOf(address(this)) >= totalWegl, "Contract Low Bal");
uint256 burnAmount = (totalWegl * 5) / 100;
uint256 userAmount = totalWegl - burnAmount;
if (msg.sender == COMPANY_ID) {
// ...
} else {
_safeTransfer(weglToken, msg.sender, userAmount);
}
emit Withdraw(msg.sender, userAmount, payoutUSD);
}
function getWeglAmountFromUsd(uint256 _usdAmount) public view returns (uint256) {
address[] memory path = new address[](2);
path[0] = address(usdtToken);
path[1] = address(weglToken);
return pancakeRouter.getAmountsOut(_usdAmount, path)[1]; // <-- VULNERABILITY
}
Why It’s Vulnerable
Expected behavior: a withdrawal contract that tracks balances internally in USD should redeem WEGL using a stable conversion source, a stored exchange rate, or a mechanism that cannot be worsened by the same withdrawal sequence. One withdrawal should not make the next user with the same USD balance receive more WEGL just because the previous recipient dumped into the same AMM pool.
Actual behavior: withdraw() zeroes availableWalletUSD, then converts that USD amount to WEGL through PancakeSwap router getAmountsOut() on the live WEGL/USDT pool. The trace shows each helper immediately selling its received WEGL into the same pool, so the spot quote observed by the next withdraw() returns a larger WEGL amount for the same USD-denominated balance.
This makes the primary flaw a logic_error, with price_manipulation as the secondary technique. The attack does not rely on reentrancy or missing auth in withdraw(); it relies on coupling payout sizing to a manipulable spot price that the attacker moves between identical withdrawal calls in the same transaction.
Attack Execution
High-Level Flow
- The attacker EOA called an orchestrator contract.
- The orchestrator invoked 11 helper contracts sequentially.
- Each helper called the White Eagle contract’s
withdraw()function. withdraw()priced the helper’s USD-denominated wallet balance into WEGL using PancakeSwap’s livegetAmountsOut()quote.- The withdrawal contract burned 5% of the computed WEGL and transferred the remainder to the helper.
- The helper immediately swapped all received WEGL to USDT through PancakeSwap and sent the USDT to the attacker’s profit receiver.
- Each sale pushed the WEGL/USDT spot price further down, so the next helper’s identical withdrawal redeemed more WEGL for its USD balance.
- Repeating this 11 times drained
9888.680557825521425533 WEGLfrom the withdrawal contract.
Detailed Call Trace
0xcd935e0462c5b32ee4c11fb5e2d5179508ee5d7e→0xfc565edbfa06ee13edfa7b8b4677f89ab2382854claim()(0x4e71d92d) viaCALL.0xfc565edbfa06ee13edfa7b8b4677f89ab2382854→ helper0x5650c7a41ef11dfa30dc295fc4d857b7c9bbc87aClaim(bool)(0xe60b3625) viaCALL.- helper →
0x0079517e4157f95cefda99d295fd74fc9b9896ebwithdraw()(0x3ccfd60b) viaCALL.- withdrawal contract → router
0x10ed43c718714eb63d5aa57b78b54704e256024egetAmountsOut(uint256,address[])(0xd06ca61f) viaSTATICCALL.- router → pair
0x9247a22981ad64e9bd1d8b9b303a2122cd88838cgetReserves()(0x0902f1ac) viaSTATICCALL.
- router → pair
- withdrawal contract → WEGL
0x5722ce859d00d6c59354c0750263180ffdc8ab7fbalanceOf(address)(0x70a08231) viaSTATICCALL. - withdrawal contract → WEGL
burn(uint256)(0x42966c68) viaCALL. - withdrawal contract → WEGL
transfer(address,uint256)(0xa9059cbb) to helper viaCALL.
- withdrawal contract → router
- helper → WEGL
balanceOf(address)(0x70a08231) viaCALL. - helper → router
swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256)(0x5c11d795) viaCALL.- router → WEGL
transferFrom(address,address,uint256)(0x23b872dd) viaCALL. - router → pair
getReserves()(0x0902f1ac) viaSTATICCALL. - router → pair
swap(uint256,uint256,address,bytes)(0x022c0d9f) viaCALL.- pair → USDT
transfer(address,uint256)(0xa9059cbb) to0xa0d511169468ffb4dc986dbb7b58fb7fc190102bviaCALL.
- pair → USDT
- router → WEGL
- helper →
- The same helper pattern repeats 10 more times through helpers
0x316350633c88caeb464911354f6431dc2948f84d,0x300270ee7353069b1841a5f6d676e99bbf8b9c38,0x4e76db7e93f4c5c52e0d6ba88c2490a49a3626a9,0x141379b7e1d5d272e05e00e58bf88efd1ddbdf3b,0x14a61089e423c3845c411fa33461fe31f90ea3e5,0xe1915a78ba553f310189e3071e5407a3c9288664,0x7c8186a60b7edcb2d6f4e29aab183f20c5267575,0x9e290f287f64e5fede397b1735b0e4885e5f8927,0xb758b842f35dc4bf9c231c36a06a1355d3779b8d, and0xba4d2e4300b227245701d2c5bf93948fb5c30e71.
The recovered orchestrator confirms this batching behavior: 0xfc565edbfa06ee13edfa7b8b4677f89ab2382854/recovered.sol hard-codes 11 helper calls, and each helper’s recovered code shows Claim(bool) calling withdraw() and then swapping WEGL to USDT for profit receiver 0xa0d511169468ffb4dc986dbb7b58fb7fc190102b.
Financial Impact
The primary victim was the White Eagle withdrawal contract, which lost 9888.680557825521425533 WEGL according to funds_flow.json. The paired PancakeSwap pool absorbed 9188.709810105814000167 WEGL, while 699.970747719707425366 WEGL was burned across the withdrawal and transfer path.
The profit receiver 0xa0d511169468ffb4dc986dbb7b58fb7fc190102b gained 65645.944170470965224333 USDT across the 11 swaps. The largest single payout in the trace was 11719.558694305319350229 USDT, and later payouts declined as pool state changed, which matches the attack pattern of repeatedly converting the same internal USD logic into progressively more WEGL while extracting external USDT liquidity.
Because the payout asset was the protocol’s own WEGL inventory, the exploit directly impaired the solvency of the withdrawal path. The contract’s status field in receipt.json is 0x1, confirming the full drain sequence executed successfully in a single transaction.
Evidence
receipt.json:1878shows transaction status0x1.trace_callTracer.jsonshowswithdraw()(0x3ccfd60b) called 11 times, each followed by a helper swap through PancakeSwap router and pair.selectors.jsonresolves the key selectors used in the report:claim(),Claim(bool),withdraw(),getAmountsOut(uint256,address[]),swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256), andswap(uint256,uint256,address,bytes).funds_flow.jsonrecords the withdrawal contract’s net loss of9888.680557825521425533 WEGLand the profit receiver’s gain of65645.944170470965224333 USDT.receipt.jsonlogs confirm the burn-and-transfer pattern for each withdrawal: WEGL is first burned from the withdrawal contract, then transferred to the helper, then transferred from the helper into the Pancake pair.