# Voters will lose all bribe rewards forever if they do not claim their rewards after the last bribing period

BribeRewarder.claim loops to Voter's latest finished period, so once two periods pass after _lastVotingPeriod the _rewards array index reverts, permanently locking all unclaimed voter bribes.

- Payout: Contest reward
- Severity: high
- Program: Magicsea
- Credited: ChinmayF
- Disclosed: 2024-07-15
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2024-06-magicsea-judging/issues/164
- Library page: https://bugbountylibrary.com/r/sherlock%3A2024-06-magicsea%3AH-4
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:business-logic vuln:dos vuln:reward-distribution

**Target:** BribeRewarder.sol claim() / _modify() reward indexing
**Root cause:** claim() iterates i from _startVotingPeriod to Voter.getLatestFinishedPeriod() without capping at _lastVotingPeriod; _modify indexes _rewards[periodId - _startVotingPeriod], but _rewards only has (lastID - startID + 2) elements, so once endPeriod exceeds _lastVotingPeriod+1 the index is out of bounds and the whole claim reverts.
**Steps:**
1. Deploy BribeRewarder with _startVotingPeriod=1, _lastVotingPeriod=5; _rewards length = 5-1+2 = 6 (indices 0..5).
2. Vote in periods 1-5 so rewards accrue for the tokenId.
3. Let periods 6 and 7 finish; Voter.getLatestFinishedPeriod() returns 7.
4. Call `claim(tokenId)`: loop reaches i=7, `_indexByPeriodId(7)` = 6, `_rewards[6]` reverts (out of bounds).
5. All prior unclaimed rewards for periods 1-5 are now permanently unclaimable.
**How found:** Code-reading of claim()'s loop bound versus _modify()'s array indexing: noticed endPeriod comes from Voter (unbounded, ever-increasing) while _rewards is sized only to _lastVotingPeriod, and traced the off-by-period boundary to lastVotingPeriod+2.
**Exploitation:** No attacker needed; any voter who fails to claim within two periods after the last bribing period triggers the revert on every subsequent claim call, permanently forfeiting accrued bribes which remain stuck in the contract.
**Insight:** When a claim/withdraw loop's upper bound comes from an external, monotonically increasing counter (global epoch) but indexes a locally-sized array, check the array length vs the max reachable index; the revert bricks all prior claims, not just the out-of-range period.
