20,000 USDC
View results
Submission Details
Severity: high
Valid

`buyLoan()` should check if `msg.sender` is the pool owner.

Summary

A malicious user can call buyLoan() with another's pool and break the repayment mechanism.

Vulnerability Details

buyLoan() is used to buy loans under the active auction.

function buyLoan(uint256 loanId, bytes32 poolId) public {
...
// update the loan with the new info
loans[loanId].lender = msg.sender; //@audit msg.sender should be pool owner
loans[loanId].interestRate = pools[poolId].interestRate;
loans[loanId].startTimestamp = block.timestamp;
loans[loanId].auctionStartTimestamp = type(uint256).max;
loans[loanId].debt = totalDebt;
emit Borrowed(
loan.borrower,
msg.sender,
loanId,
loans[loanId].debt,
loans[loanId].collateral,
pools[poolId].interestRate,
block.timestamp
);
emit LoanBought(loanId);
}

But it doesn't validate if msg.sender is the pool owner and sets msg.sender as a lender of the loan.

As a result, the loan will save the wrong address as a lender and the repaying logic won't work.

  1. There is a normal loan between lender A and borrower B. And another lender AA has a similar pool to A's.

  2. After Astarts an auction with B's loan, an attacker calls buyLoan() with AA's pool.

  3. Then the loan's new lender will be the attacker instead of AA here although the attacker doesn't have any pools.

  4. Also, when B tries to repay using repay(), it will revert because it generates the wrong poolId here with the wrong lender address(attacker).

So the borrower can't repay his loan forever.

Impact

Borrowers wouldn't repay their loans forever.

Tools Used

Manual Review

Recommendations

buyLoan() should validate msg.sender is the pool owner.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.