# Malicious user can flood a user's staked locks array and prevent the user from withdrawing due to Out Of Gas revert

Anyone can stake tiny LP amounts on behalf of a victim, bloating their userLocks array until withdrawExpiredLocks loops out of gas, permanently blocking withdrawal.

- Payout: Contest reward
- Severity: high
- Program: Defi App
- Credited: pineneedles
- Disclosed: 2025-03-27
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_defi_app_february2025.pdf#3.1.4
- Library page: https://bugbountylibrary.com/r/cantina%3Adefi_app_february2025%3A3.1.4
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:cantina sev:high tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** MultiFeeDistribution staking contract (MFDBase/MFDLogic)
**Root cause:** stake() permits staking on behalf of arbitrary addresses, pushing a StakedLock into the victim's userLocks array; withdrawal functions iterate the entire array with _limit = userLocks[msg.sender].length, so unbounded array growth causes OOG reverts.
**Steps:**
1. Call `lockzap.zapOnBehalf(amount, 0, victim, minLpTokens)` with a tiny LP amount (e.g. 1e10) repeatedly from an attacker address.
2. Each call pushes a new StakedLock into `$.userLocks[victim]`, growing the array without the victim's consent.
3. Repeat ~500+ times until array length makes iteration exceed block gas limit.
4. Victim calls `withdrawExpiredLocks()`; it invokes `MFDLogic.handleWithdrawOrRelockLogic($, msg.sender, false, $.userLocks[msg.sender].length)` and reverts Out Of Gas.
5. Victim's expired locks remain permanently unwithdrawable.
**How found:** Code review of MFDBase.stake() noting it accepts an on-behalf recipient, combined with observing that withdrawExpiredLocks passes the full array length as the iteration limit — unbounded growth implies gas exhaustion.
**Exploitation:** Attacker spends minimal LP per stake-on-behalf call to inflate the victim's userLocks array; the victim's withdrawal path iterates the whole array and reverts OOG, locking their staked funds.
**Insight:** When a staking/deposit function accepts an arbitrary beneficiary, check every downstream loop bounded by that beneficiary's array length; griefing via array inflation is cheap and permanent if no cap exists.
