# Unable to claim vesting due to unbounded timelock loop

Vesting.vest() lacks beneficiary check, letting anyone spam tiny timelocks into a victim's array until claim() loops past gas limit, locking vestments.

- Payout: Audit contest
- Severity: high
- Program: Boot Finance
- Found by: nathaniel
- Disclosed: 2022-01-21
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-11-bootfinance-findings/issues/120
- Library page: https://bugbountylibrary.com/r/c4%3A2021-11-bootfinance%3AH-08
- Tags: area:web3 domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:dos

**Target:** Vesting.sol smart contract (vest/claim/_claimableAmount)
**Root cause:** vest() does not require msg.sender == beneficiary and imposes no minimum amount, so anyone can append unbounded timelocks to any beneficiary's array; _claimableAmount() iterates the whole array, so claim() eventually exceeds the block gas limit.
**Steps:**
1. Attacker calls `vest(_beneficiary, 1 wei)` repeatedly for a victim beneficiary, each call pushing a new entry to `timelocks[_beneficiary]`.
2. Array grows large enough that iterating it in `_claimableAmount()` exceeds block gas limit.
3. Victim calls `claim()`; loop reverts out-of-gas, vestment unclaimable.
4. Repeat across all beneficiaries to lock all vestments.
**How found:** Manual code review: noticed vest() lacks a beneficiary==msg.sender check and that _claimableAmount() loops over an unbounded array, connecting the two into a gas-griefing DoS.
**Exploitation:** Permissionless repeated vest() calls with minute amounts bloat each beneficiary's timelocks array; claim() then reverts on gas, permanently denying vesting withdrawal.
**Escalation:** Applied to every beneficiary to lock all vestments protocol-wide.
**Insight:** When a permissionless function appends to a per-user array that another function iterates, check for unbounded-growth gas griefing; look for missing msg.sender==owner checks on array-push paths.
