# dMute.sol: Attacker can push lock items to victim's array such that redemptions are forever blocked

dMute.LockTo lets anyone lock tokens for any address, pushing unbounded entries into the victim's _userLocks array so RedeemTo/GetUnderlyingTokens loop out of gas, permanently blocking redemptions.

- Payout: Contest reward
- Severity: high
- Program: Mute.io
- Credited: HollaDieWaldfee
- Disclosed: 2023-04-27
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-03-mute-findings/issues/6
- Library page: https://bugbountylibrary.com/r/c4%3A2023-03-mute%3AH-03
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** dMute.sol staking/lock contract on zkSync
**Root cause:** LockTo permits locking tokens on behalf of an arbitrary address, appending to that user's _userLocks array; RedeemTo and GetUnderlyingTokens iterate the whole array, so a large array exceeds the block gas limit.
**Steps:**
1. Approve dMute to spend MUTE from attacker account.
2. Loop `LockTo(100, 604800, victim)` 5000 times (or ~2000 on zkSync's 12.5M gas limit), each pushing a UserLockInfo to victim's array.
3. Wait for lock time to elapse.
4. Victim calls `Redeem([0])`; the loop over _userLocks exceeds block gas limit and reverts out-of-gas, blocking redemption.
**How found:** Noticed LockTo accepts an arbitrary `to` address, then traced that RedeemTo and GetUnderlyingTokens loop over the per-user _userLocks array, hypothesizing unbounded array growth could exceed block gas limits; validated with a Hardhat test adding 5000 locks.
**Exploitation:** Attacker spends negligible MUTE (100 wei per lock) plus cheap zkSync gas to spam LockTo against a victim address, inflating their _userLocks array until RedeemTo and GetUnderlyingTokens always revert out of gas, permanently locking the victim's MUTE.
**Escalation:** Griefing extends to MuteBond and MuteAmplifier which depend on the locking functionality, making those features unusable.
**Insight:** When a deposit/lock function accepts a beneficiary address, check whether per-user arrays it appends to are iterated in withdrawal/view functions — unbounded growth becomes a cheap griefing DoS even without profit.
