When a user borrows, LendingPool transfers the required crvusd from the reserve. If reserves are insufficient, it withdraws the shortfall from CurveVault. However, the borrowed crvusd is transferred from the reserve address, while the withdrawn funds from CurveVault are mistakenly sent to LendingPool instead of the reserve address.
LendingPool::borrow calls _ensureLiquidity() to ensure sufficient liquidity for the borrower.
If liquidity is insufficient, _withdrawFromVault() withdraws the missing amount from CurveVault:
Here, the receiver parameter is set to address(this), meaning the withdrawn crvusd is sent to LendingPool instead of the reserve address.
The CurveVault::withdraw function sends tokens to the specified receiver, which in this case is incorrect (LendingPool).
Meanwhile, in LendingPool::borrow, crvusd is transferred from reserve.reserveRTokenAddress (not LendingPool) to the borrower. This mismatch causes DoS of the LendingPool::borrow as well as LendingPool::withdraw.
The flaw results in a Denial of Service (DoS) for borrowing and withdrawing.
VSCode, Manual Research
Fix the receiver argument in the CurveVault::withdraw call
Alternatively, transfer the withdrawn tokens to the reserve after withdrawal:
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.