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

  1. The attacker EOA called an orchestrator contract.
  2. The orchestrator invoked 11 helper contracts sequentially.
  3. Each helper called the White Eagle contract’s withdraw() function.
  4. withdraw() priced the helper’s USD-denominated wallet balance into WEGL using PancakeSwap’s live getAmountsOut() quote.
  5. The withdrawal contract burned 5% of the computed WEGL and transferred the remainder to the helper.
  6. The helper immediately swapped all received WEGL to USDT through PancakeSwap and sent the USDT to the attacker’s profit receiver.
  7. Each sale pushed the WEGL/USDT spot price further down, so the next helper’s identical withdrawal redeemed more WEGL for its USD balance.
  8. Repeating this 11 times drained 9888.680557825521425533 WEGL from the withdrawal contract.

Detailed Call Trace

  • 0xcd935e0462c5b32ee4c11fb5e2d5179508ee5d7e0xfc565edbfa06ee13edfa7b8b4677f89ab2382854 claim() (0x4e71d92d) via CALL.
    • 0xfc565edbfa06ee13edfa7b8b4677f89ab2382854 → helper 0x5650c7a41ef11dfa30dc295fc4d857b7c9bbc87a Claim(bool) (0xe60b3625) via CALL.
      • helper → 0x0079517e4157f95cefda99d295fd74fc9b9896eb withdraw() (0x3ccfd60b) via CALL.
        • withdrawal contract → router 0x10ed43c718714eb63d5aa57b78b54704e256024e getAmountsOut(uint256,address[]) (0xd06ca61f) via STATICCALL.
          • router → pair 0x9247a22981ad64e9bd1d8b9b303a2122cd88838c getReserves() (0x0902f1ac) via STATICCALL.
        • withdrawal contract → WEGL 0x5722ce859d00d6c59354c0750263180ffdc8ab7f balanceOf(address) (0x70a08231) via STATICCALL.
        • withdrawal contract → WEGL burn(uint256) (0x42966c68) via CALL.
        • withdrawal contract → WEGL transfer(address,uint256) (0xa9059cbb) to helper via CALL.
      • helper → WEGL balanceOf(address) (0x70a08231) via CALL.
      • helper → router swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256) (0x5c11d795) via CALL.
        • router → WEGL transferFrom(address,address,uint256) (0x23b872dd) via CALL.
        • router → pair getReserves() (0x0902f1ac) via STATICCALL.
        • router → pair swap(uint256,uint256,address,bytes) (0x022c0d9f) via CALL.
          • pair → USDT transfer(address,uint256) (0xa9059cbb) to 0xa0d511169468ffb4dc986dbb7b58fb7fc190102b via CALL.
    • The same helper pattern repeats 10 more times through helpers 0x316350633c88caeb464911354f6431dc2948f84d, 0x300270ee7353069b1841a5f6d676e99bbf8b9c38, 0x4e76db7e93f4c5c52e0d6ba88c2490a49a3626a9, 0x141379b7e1d5d272e05e00e58bf88efd1ddbdf3b, 0x14a61089e423c3845c411fa33461fe31f90ea3e5, 0xe1915a78ba553f310189e3071e5407a3c9288664, 0x7c8186a60b7edcb2d6f4e29aab183f20c5267575, 0x9e290f287f64e5fede397b1735b0e4885e5f8927, 0xb758b842f35dc4bf9c231c36a06a1355d3779b8d, and 0xba4d2e4300b227245701d2c5bf93948fb5c30e71.

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:1878 shows transaction status 0x1.
  • trace_callTracer.json shows withdraw() (0x3ccfd60b) called 11 times, each followed by a helper swap through PancakeSwap router and pair.
  • selectors.json resolves the key selectors used in the report: claim(), Claim(bool), withdraw(), getAmountsOut(uint256,address[]), swapExactTokensForTokensSupportingFeeOnTransferTokens(uint256,uint256,address[],address,uint256), and swap(uint256,uint256,address,bytes).
  • funds_flow.json records the withdrawal contract’s net loss of 9888.680557825521425533 WEGL and the profit receiver’s gain of 65645.944170470965224333 USDT.
  • receipt.json logs 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.