An attacker can steal any loan opening for auction by executing the Lender::buyLoan() and specifying the poolId parameter to a forged/fake pool. This vulnerability can even cause the protocol to become insolvent because an attacker moves out the stolen loans' loanToken and/or collateralToken tokens.
Root cause: the buyLoan() lacks verification that the loan's loanToken and collateralToken must be identical to the new pool.
Therefore, an attacker can buy the loan using another pool of different loanToken/collateralToken pair.
To elaborate on this vulnerability, assume that a loan of 1 WETH (loanToken) / 2000 USDC (collateralToken) is opened for auction. An attacker can execute the buyLoan() to buy the loan by pointing to a pool of DAI (loanToken) / USDC (collateralToken). In this way, the attacker can steal the loan's debt of $2000+ using small DAI tokens (totalDebt = 1 + lenderInterest + protocolInterest).
Balance subtraction from a forged pool: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L489
The attacker becomes a new lender: https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L518
An attacker can steal any loan opening for auction by executing the buyLoan() and specifying the poolId parameter to a forged pool. The forged pool can even point to a pair of fake loanToken and collateralToken, which has worth $0.
This vulnerability can even cause the protocol to become insolvent because an attacker moves out the stolen loans' loanToken and/or collateralToken tokens. Hence, I consider this vulnerability a high-risk issue.
Manual Review
I recommend verifying that the loan's loanToken and collateralToken must be identical to the new pool, as shown below.
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.