Summary
Lender.borrow() uses pool.interestRate
as loan's interest rate and is prone to frontrunning by malicious lender who wants to increase interest rate.
Vulnerability Details
https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L221-L226
function updateInterestRate(bytes32 poolId, uint256 interestRate) external {
if (pools[poolId].lender != msg.sender) revert Unauthorized();
if (interestRate > MAX_INTEREST_RATE) revert PoolConfig();
pools[poolId].interestRate = interestRate;
emit PoolInterestRateUpdated(poolId, interestRate);
}
https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L249-L260
function borrow(Borrow[] calldata borrows) public {
...
Loan memory loan = Loan({
lender: pool.lender,
borrower: msg.sender,
loanToken: pool.loanToken,
collateralToken: pool.collateralToken,
debt: debt,
collateral: collateral,
interestRate: pool.interestRate,
startTimestamp: block.timestamp,
auctionStartTimestamp: type(uint256).max,
auctionLength: pool.auctionLength
});
...
}
Impact
Borrower will have to pay higher interest rate than previously seen without any notice.
Tools Used
Manual Review
Recommendations
Borrower should specify expected interest rate when borrowing, and it should be equal to pool's interest rate.
struct Borrow {
bytes32 poolId;
uint256 debt;
uint256 collateral;
+
+ uint256 interestRate;
}
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;
Pool memory pool = pools[poolId];
+ if (borrows[i].interestRate != pool.interestRate) revert WrongInterestRate();
...
}