# griefing / blocking / delaying users to withdraw

WithdrawHook resets per-user withdraw limits globally for only the first caller each epoch, letting any user grief others into waiting a full period to withdraw.

- Payout: Contest reward
- Severity: high
- Program: prePO
- Credited: zaskoh
- Disclosed: 2023-01-27
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-prepo-findings/issues/116
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-prepo%3AH-01
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:dos

**Target:** Solidity WithdrawHook contract (withdraw limit accounting)
**Root cause:** A single global lastUserPeriodReset timestamp is updated only by the first withdrawer in a new epoch, so other users' userToAmountWithdrawnThisPeriod is never reset and their prior-epoch usage persists.
**Steps:**
1. Deploy WithdrawHook; set userPeriodLength, userWithdrawLimitPerPeriod, disable global limits.
2. User A withdraws exactly userWithdrawLimitPerPeriod via `hook(user, limit, limit)`.
3. Advance time past lastUserPeriodReset + userPeriodLength.
4. User B calls `hook(user2, limit, limit)` first, consuming the epoch reset.
5. User A calls `hook(user, 1, 1)` -> reverts 'user withdraw limit exceeded' despite new epoch.
**How found:** Compared documented behavior (all users' withdraw amounts reset each epoch) against implementation, noticing lastUserPeriodReset is a single storage slot updated only for the first caller.
**Exploitation:** Any user (or attacker) submits the first withdraw transaction of a new epoch, consuming the global reset; users who hit their limit in the prior epoch remain blocked until they are first in a subsequent epoch, delaying fund withdrawal.
**Insight:** When a per-user rate limit shares a single global reset timestamp, only the first caller per period gets reset; check whether reset state is keyed per-account.
