A pool lender can fully drain another user's pool by abusing buyLoan function.
Upon buying a loan, all a pool.lender passes as arguments in the function is the id of the loan they want to buy. This could be problematic as the loan could be subject to heavy changes.
Consider the following scenario:
User A creates a pool with max interest rate.
From another wallet, the same user takes a borrow for 1000 USDC and gives 3000 USDT as collateral
User A calls startAuction for this loan
User B sees the loan on auction and since it has high interest rate and is well-collateralized, decides to buy it.
User B calls buyLoan and passes to corresponding loanId.
User A sees the pending transaction and front-runs it and changes his pool.maxLoanRatio to type(uint256).max (basically allowing for loans not sufficiently backed up by collateral)
After changing the maxLoanRatio, user A calls refinance and sets the loan debt to user B's pool balance and changes the collateral to 1 USDT.
After doing so, user A changes maxLoanRatio back to its original value and once again calls startAuction with the same loanId.
Considering steps 6-8 all executed before user B's buyLoan, user B's call now executes and they've bought a borrow for all of their pool balance, backed up by pretty much no collateral.
User A successfully executed the attack and has now taken a huge borrow which they have no incentive to repay as there isn't any valuable collateral attached to it.
User A can then either withdraw their funds from their pool or repeat the attack.
Pool lender can drain other pools.
Manual review
Add the following check to buyLoan
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.