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

Malicious lender can force users to take on a loan with a higher interest rate than they intended

Summary

A malicious lender can force the borrower to accept an interest rate he doesn't agree with by frontrunning the transaction.

Vulnerability Details

In the following scenario, a malicious lender can force the borrower into accepting a loan with a higher interest rate than anticipated by frontrunning the transaction.

  1. The malicious lender creates a pool with a very attractive interest rate (e.g., setting a 0% interest rate) using the setPool function.

  2. Suppose Bob, an honest user, observes the pool offering a remarkably low interest rate and proceeds to submit a borrowing transaction by calling the borrow function.

  3. Once the malicious lender detects Bob's transaction in the mempool, he immediately calls updateInterestRate (e.g., setting a 1000% interest rate) with a higher gas amount than Bob's transaction to guarantee that his transaction is executed first.

Bob will end up with being frontrunned by the lender, and will take on a loan featuring an exorbitant 1000% interest rate, significantly higher than what he initially intended or agreed upon.

Impact

As a result of this vulnerability, users may unknowingly accept loans with significantly higher interest rates than they initially agreed upon, leading to potential financial losses and undermining user trust in the lending platform.

Tools Used

Manual Review.

Recommendations

Modify the Borrow struct in Structs.sol by adding an interestRate parameter. This change will require borrowers to explicitly specify the interest rate they agree to when initiating a borrowing transaction.

https://github.com/Cyfrin/2023-07-beedle/blob/main/src/utils/Structs.sol#L25-L32

struct Borrow {
/// @notice the pool ID to borrow from
bytes32 poolId;
/// @notice the amount to borrow
uint256 debt;
/// @notice the amount of collateral to put up
uint256 collateral;
+ /// @notice the interest rate per year the user is agreeing to
+ uint256 interestRate;
}

In the borrow function of the Lender.sol contract, include a validation step to ensure that the interest rate specified by the borrower matches the interest rate set in the pool. This prevents lenders from imposing arbitrary interest rates on borrowers

https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L234-L244

function borrow(Borrow[] calldata borrows) public {
for (uint256 i = 0; i < borrows.length; i++) {
bytes32 poolId = borrows[i].poolId;
uint256 debt = borrows[i].debt;
uint256 collateral = borrows[i].collateral;
+ uint256 interestRate = borrows[i].interestRate;
...
// validate the loan
if (debt < pool.minLoanSize) revert LoanTooSmall();
if (debt > pool.poolBalance) revert LoanTooLarge();
if (collateral == 0) revert ZeroCollateral();
+ if (interestRate != pool.interestRate) revert PoolConfig();
...
}
}

Support

FAQs

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