# Delegate in IncentiveVoting can lock user's tokens forever

Bima delegate fills a user's activeVotes array with 10,000 zero-point votes, making unfreeze() exceed block gas limit and permanently locking tokens.

- Payout: Contest reward
- Severity: medium
- Program: Bima
- Credited: T1MOH
- Disclosed: 2025-02-05
- Write-up quality: 7/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_bima_december2024.pdf#3.2.9
- Library page: https://bugbountylibrary.com/r/cantina%3Abima_december2024%3A3.2.9
- Tags: domain:web3 impact:dos kind:contest platform:cantina sev:medium tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic vuln:dos

**Target:** IncentiveVoting / TokenLocker voting contracts
**Root cause:** vote() has no cap on total stored activeVotes length, and unfreeze() iterates the entire array in _removeVoteWeightsFrozen, so a bloated array makes unfreeze uncallable within block gas limit.
**Steps:**
1. User calls `tokenLocker.lock`, `tokenLocker.freeze`, and `incentiveVoting.setDelegateApproval(delegate, true)`.
2. Delegate calls `incentiveVoting.registerAccountWeight(user, 0)` then repeatedly `incentiveVoting.vote(user, votes, false)` with 1800 zero-point votes for id 0, ~5 times (~121M gas).
3. User calls `tokenLocker.unfreeze(false)`, which loops all stored votes and consumes ~30.7M gas, exceeding the 30M block gas limit.
4. Tokens remain locked permanently; attack cost ~$2700 at 7 gwei and $3200/ETH.
**How found:** Reviewer noted delegate permissions are scoped to voting actions, then traced that vote() writes unbounded entries into activeVotes while unfreeze() iterates the whole array, hypothesizing a gas-griefing lock.
**Exploitation:** A trusted delegate abuses its voting permission to append cheap zero-point votes to the victim's activeVotes array until unfreeze() gas exceeds the block gas limit, bricking the victim's locked tokens at a cost of ~$2700 per victim.
**Insight:** When a permissioned actor can append to an array that a victim-triggered function later iterates, check whether array growth can push the victim's call past the block gas limit — cheap zero-value entries make this a low-cost permanent DoS.
