The buyLoan function does not validate if the caller (msg.sender) is the actual owner of the pool with the given pool id (poolId). This leads to the inability to repay/seize/auction/refinance the loan and the funds being stuck (for both the lender and the borrower).
An auctioned loan can be bought with the buyLoan function, providing the loan id (loanId) and the pool id (poolId) for the pool to move the loan to. However, it is currently not checked if the caller, msg.sender is the actual pool owner. Consequently, anyone can call the buyLoan function for a loan that is currently being auctioned. This will assign the msg.sender as the new lender of the loan (see line 518). Therefore, anyone can be the new lender without having a pool but utilizing someone else's pool.
As a result, whenever the pool id for a loan is determined as the keccak256 hash of the loan.lender, loan.loanToken, and the loan.collateralToken (e.g., by using the getPoolId function), this pool id is potentially different than the actual pool id that was supplied to the buyLoan call.
Subsequently, when the borrower attempts to repay the loan, the determined pool id will use the new loan.lender, which is set to the incorrect lender address and points to a pool that does not yet exist. The repay function will then revert in line 314 due to subtracting the loan debt from outstandingLoans, which is 0.
Ultimately, the loan is stuck, and any further actions are not possible.
Determining the pool id of such a bought loan will be incorrect and not the actual pool id that was supplied to the buyLoan function. This incorrect pool id is potentially pointing to a non-existent pool, causing the borrower to be unable to repay the loan due to reverting in line 314 of the repay function caused by insufficient outstandingLoans (i.e., zero).
Moreover, attempting to use buyLoan will fail as well due to the same reason as above.
Effectively, both the lender and the borrower have their funds stuck.
Manual Review
Consider verifying that the caller (msg.sender) is the actual lender of the given poolId by checking pools[poolId].lender == msg.sender in the buyLoan function.
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.