The WithdrawalPool::updateWithdrawalBatchIdCutoff function is designed to update the withdrawalBatchIdCutoff, which helps efficiently return data in getBatchIds by skipping old withdrawal batches. However, a malicious user can exploit this function by delaying their token withdrawal indefinitely, preventing the cutoff from advancing. This manipulation can lead to a DoS situation when the function tries to iterate over a large number of withdrawals, risking an out-of-gas error.
The updateWithdrawalBatchIdCutoff function iterates over the queuedWithdrawals array to find the first unprocessed or partially filled withdrawal and updates the withdrawalIdCutoff accordingly. Since numWithdrawals is an ever-growing array, the function stores newWithdrawalIdCutoff to avoid recalculating from the beginning each time.
Here's the relevant code section:
A malicious user whose withdrawal request is at the withdrawalIdCutoff can intentionally delay withdrawing their tokens. This causes the list of queued withdrawals to grow without updating the cutoff. Eventually, the loop will iterate over too many unprocessed withdrawals, risking an out-of-gas DoS. The attack is low-cost, as the attacker can simply withdraw their tokens whenever they choose.
Illustration explaining withdrawalIdCutoff:
[0, 0, 0, 1, 0, 0, 0, 1, 1] : withdrawalIdCutoff = 2
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1] : withdrawalIdCutoff = 6
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1] : withdrawalIdCutoff = 9
If the user at the cutoff delays their withdrawal indefinitely, the difference between the current withdrawalIdCutoff and the next valid cutoff grows, making future updates to the cutoff computationally expensive.
If getBatchIds becomes unusable, users will struggle to retrieve accurate parameters for withdrawing their tokens. This makes the withdrawal process inefficient and can disrupt normal protocol operations, causing financial loss and frustration for users.
Manual
Implement a timeout or penalty system for users who do not withdraw their tokens within a reasonable timeframe. Alternatively, limit the number of iterations per transaction to prevent an out-of-gas DoS when the queue grows too large.
Let me know if you'd like any further changes!
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.