Open howlbot-integration[bot] opened 2 months ago
We're going to have to dig into this, but we're confirming. Thank you!
I am confirming as H, under the assumption that funds can't be recovered (didn't see a cancelWithdrawal
or similar option).
3docSec marked the issue as satisfactory
3docSec marked the issue as selected for report
Fixed by the mitigation for #121:
https://github.com/code-423n4/2024-08-wildcat-findings/issues/121#issuecomment-2406134173
Lines of code
https://github.com/code-423n4/2024-08-wildcat/blob/main/src/market/WildcatMarketWithdrawals.sol#L248
Vulnerability details
Impact
User could withdraw more than supposed to and force last user's withdraw to fail.
Proof of Concept
Within Wildcat, withdraw requests are put into batches. Users first queue their withdraws and whenever there's sufficient liquidity, they're filled at the current rate. Usually, withdraw requests are only executable after the expiry passes and then all users within the batch get a cut from the
batch.normalizedAmountPaid
proportional to the scaled amount they've requested a withdraw for.This makes sure that the sum of all withdraws doesn't exceed the total
batch.normalizedAmountPaid
.However, this invariant could be broken, if the market is closed as it allows for a batch's withdraws to be executed, before all requests are added.
Consider the market is made of 3 lenders - Alice, Bob and Laurence.
state.normalizedUnclaimedWithdrawals
Note: marking this as High severity as it both could happen intentionally (attacker purposefully queuing numerous low-value withdraws to cause rounding down) and also with normal behaviour in high-value closed access markets where a user's withdraw could easily be in the hundreds of thousands.
Also breaks core invariant:
Adding a PoC to showcase the issue:
Tools Used
Manual review
Recommended Mitigation Steps
Although it's not a clean fix, consider adding a
addNormalizedUnclaimedRewards
function which can only be called after a market is closed. It takes token from the user and increases the global variablestate.normalizedUnclaimedRewards
. The invariant would remain broken, but it will make sure no funds are permanently stuck.Assessed type
Under/Overflow