# Level: duplicate epoch array in claimMultiple drains rewards

Level's referral controller lacked duplicate-epoch checks in claimMultiple, letting an attacker claim the same epoch reward repeatedly and drain ~$1M in LVL.

- Payout: Real-world hack
- Severity: high
- Program: Level
- Analysis by: DeFiHackLabs
- Disclosed: 2023-05-02
- Write-up quality: 7/10
- Original: https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/2023-05/Level_exp.sol
- Library page: https://bugbountylibrary.com/r/dhl%3A20230502-level
- Tags: area:web3 domain:web3 impact:funds-loss kind:incident platform:defihacklabs sev:high tech:evm tech:solidity vuln:accounting-error vuln:business-logic vuln:reward-distribution

**Target:** LevelReferralControllerV2 reward claim contract on BSC
**Root cause:** claimMultiple iterated over a caller-supplied epoch array without deduplicating entries, so the same epoch could be claimed many times in one call. The claimable accounting was not decremented per epoch within the loop.
**Steps:**
1. Deploy 15 Referral contracts pointing to an Exploiter contract and 15 pointing to the attacker, then call `setReferrer` to build referral points.
2. Flash-loan 300 WBNB from DODO and wash-trade WBNB/USDT through the Level pool via `swap` to inflate trading points.
3. Advance time, call `setEnableNextEpoch(true)` and `nextEpoch()` from the privileged account to open the next epoch.
4. Call `claim(tokenID, address(this))` and `exploiter.claim(tokenID)` to claim the first epoch.
5. Build an array of 2000 identical epoch IDs and call `LevelReferralControllerV2.claimMultiple(_epoches, address(this))` plus `exploiter.claimMultiple(amount)`.
6. Repeat the duplicate-epoch claim loop 11 times with small time warps to drain LVL rewards.
**How found:** Likely spotted that claimMultiple accepts an arbitrary uint256[] of epochs and pays per element without tracking which epochs were already claimed in the same call, enabling duplicate entries.
**Exploitation:** Attacker flash-loaned 300 WBNB, wash-traded to accumulate referral/trading points, then called claimMultiple with an array of 2000 copies of the same epoch ID. Because the contract did not check for duplicates, each entry paid out the epoch reward again, and the attacker repeated this across multiple calls to extract ~$1M in LVL.
**Escalation:** Repeated the duplicate-epoch claim 11 times in a loop, each time with 2000 duplicate entries, multiplying the payout.
**Insight:** When a batch-claim function takes an array of IDs, always test whether duplicate IDs are rejected or whether per-ID claimed state is updated inside the loop; a single duplicated ID can multiply the payout.

