USDS borrowers can escape liquidation infinitely #299
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-312
edited-by-warden
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/stable/CollateralAndLiquidity.sol#L154
https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/staking/StakingRewards.sol#L104-L111
Vulnerability details
Impact
USDS borrowers that should be liquidated can exploit the coolDown mechanism to prevent successful liquidations at practically no cost and for an infinite amount of time.
Vulnerability details
USDS borrowers can deposit or withdraw collateral in the protocol using the
depositCollateralAndIncreaseShare
&withdrawCollateralAndClaim
methods insideCollateralAndLiquidity.sol
contract. Both of those methods along with theliquidateUser
method of the same contract internally call_increaseUserShare
&_decreaseUserShare
, which implement a coolDown mechanism, that snapshots the last time a user has deposited/withdrawn collateral and blocks new movements for some time (1-6 hours).https://github.com/code-423n4/2024-01-salty/blob/53516c2cdfdfacb662cdea6417c52f23c94d5b5b/src/staking/StakingRewards.sol#L104-L111
The exploitable case occurs inside
CollateralAndLiquidity.liquidateUser()
which can be called by anyone to liquidate an insolvent borrower. Problem is that the function calls_decreaseUserShare
with the coolDown flag set totrue
, which makes it dependent on the last coolDown set for that borrower.Since the borrower can reset his cooldown by depositing/withdrawing he can quite easily deposit a minimum amount of wei before each liquidation call which will make
liquidateUser()
revert because the coolDown is not expiredSince the minimum deposit amount is 100 wei, it wouldn't cost the borrower anything to deposit a dust amount and reset his cooldown.
I've calculated that for a default cooldown period of 1 hour it would cost the borrower 0.000000000000145642 $ (or practically nothing) to block liquidation for a period of 30 days. Considering the coolDown period can be increased to 6 hours the cost would be even lower - about x6 lower.
Below I've coded a POC to prove all of this
Proof of Concept
Add this test to CollateralAndLiquidity.t.sol and run
forge test --rpc-url "https://rpc.sepolia.org/" --contracts src/stable/tests/CollateralAndLiquidity.t.sol --mt testPreventLiquidation -v
Here is a breakdown of the POC:
Tools Used
Manual review, Foundry
Recommended Mitigation Steps
Inside
CollateralAndLiquidity.liquidateUser()
when calling_decreaseUserShare()
change the useCooldown argument to false, so that it cannot be influenced by user depositsAssessed type
Invalid Validation
The text was updated successfully, but these errors were encountered: