# Nimbus: flash-loan price manipulation drains staking rewards

Nimbus staking reward price was manipulated via a flash-loan-funded swap on NBU_WBNB/NIMB, letting the attacker inflate GNIMB rewards and drain ~76k.

- Payout: Real-world hack
- Severity: high
- Program: - Nmbplatform
- Analysis by: DeFiHackLabs
- Disclosed: 2022-12-14
- Write-up quality: 6/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2022-12/Nmbplatform_exp.sol
- Library page: http://bugbountylibrary.com/r/dhl%3A20221214-nmbplatform
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity vuln:flash-loan vuln:oracle-manipulation vuln:reward-distribution

**Target:** StakingRewardFixedAPY / LockStakingRewardFixedAPY reward accounting and NimbusRouter NBU_WBNB/NIMB pair
**Root cause:** Staking reward value is derived from a spot price on the NBU_WBNB/NIMB AMM pair, which is manipulable within a single transaction via flash loan.
**Steps:**
1. Flash loan WBNB from DODO (0x0fe261aeE0d1C4DFdDee4102E82Dd425999065F4) via `DVM(dodo).flashLoan(flashLoanAmount, 0, address(this), new bytes(1))`.
2. In DPPFlashLoanCall, flash-swap WBNB from the NBU_WBNB/WBNB pair: `Pair.swap(flashSwapAmount, 0, address(this), new bytes(1))` where `flashSwapAmount = WBNB.balanceOf(address(Pair)) - 1e18`.
3. In BiswapCall, wrap WBNB to NBU_WBNB via `NBU_WBNB.deposit{value: address(this).balance}()` and swap NBU_WBNB->NIMB on NimbusRouter to manipulate the reward price.
4. Call `getReward()` on the three staking contracts (stakingReward1/2/3) to claim inflated GNIMB rewards.
5. Swap NIMB->NBU_WBNB and GNIMB->NBU_WBNB back on NimbusRouter, unwrap to WBNB.
6. Repay the pair flash swap `flashSwapAmount * 1000 / 998 + 1000` and repay DODO flash loan `WBNB.transfer(dodo, flashLoanAmount)`.
7. Keep remaining WBNB as profit (~76k).
**Exploitation:** Attacker flash-borrows WBNB from DODO, flash-swaps WBNB out of the NBU_WBNB/WBNB pair, wraps to NBU_WBNB, swaps into NIMB to spike the reward token price, then claims staking rewards across three staking contracts at the manipulated rate, swaps back, repays loans, and keeps the difference.
**Escalation:** Repeated across three separate staking contracts (StakingRewardFixedAPY and two LockStakingRewardFixedAPY) in one transaction to maximize drained rewards.
**Insight:** When a staking contract computes reward value from a spot AMM price (here NBU_WBNB/NIMB), a single-transaction flash loan can move that price and inflate `earned()`; check whether reward accounting reads a manipulable pair reserve rather than a TWAP.

