The withdraw() function is designed to allow users to redeem their deposited rToken by burning an equivalent amount of deToken. However, due to incorrect calculation of redeemable rToken amounts, a user could withdraw more rToken than they originally deposited, leading to an unauthorized drain of funds from the Stability Pool. The problem originates in the calculateRcrvUSDAmount() function:
The issue occurs if getExchangeRate() is manipulated or fluctuates significantly. Since the exchange rate is used to determine the amount of rToken a user can withdraw per deToken, an attacker can artificially inflate getExchangeRate() (e.g. through flash loans, governance attacks, or external market manipulations). If getExchangeRate() increases significantly, the function will compute a much higher rToken amount than the user actually deposited. As a result, when withdraw() is executed:
The check userDeposits[msg.sender] < rcrvUSDAmount is ineffective because the user may have deposited a much lower amount initially but can withdraw significantly more due to the exchange rate shift. This allows attackers to systematically drain Stability Pool reserves by repeatedly depositing rToken when the exchange rate is low and withdrawing disproportionately high amounts when the rate spikes.
Attackers can withdraw more rToken than they initially deposited, leading to an unauthorized fund drain from the Stability Pool, potentially exhausting liquidity and destabilizing the protocol.
Ensure getExchangeRate() is updated correctly and resistant to manipulation, and introduce a mechanism to cap withdrawals to the original deposit amount per user to prevent abuse.
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.