20,000 USDC
View results
Submission Details
Severity: high

Function Borrow is vulnerable to Re-enterancy by which a malicious borrower can empty the whole pool.

Summary

The Function borrow in lender.sol is vulnerable to re-enterancy by which an attacker can empty the whole lending pool as because the debt is transfered before taking the collateral tokens back to pool, which opens the gate for malicious attacker to exploit the lender contract.

Vulnerability Details

The lender.sol borrow function works by sending the debt and receiving the collateral token, but the mistake here is that the function borrow send the debt before taking the collateral token. The line 269 in lending.sol
https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L269

IERC20(loan.loanToken).transfer(msg.sender, debt - fees);

Transfer's the debt to borrower and a malicious borrower(msg.sender) can exploit it by just setting a fallback function which again calls the borrow function of lender.sol by which again the borrowing process starts and the lending pool will be unable to take collateral in return of the debt amount as the code below in lender.sol is deducting the collateral token after transfering the debt.
https://github.com/Cyfrin/2023-07-beedle/blob/main/src/Lender.sol#L270-L275

// transfer the collateral tokens from the borrower to the contract
IERC20(loan.collateralToken).transferFrom(
msg.sender,
address(this),
collateral
);

By this a malicious borrower can empty the whole pool.

Attack Scenario:

  1. Pool is started by the Lender.

  2. Malicious borrower wants to borrow and identify this and set fallback fuction as this

fallback() external payable {
if (address(Lender).balance >= 1 (LoanToken)) {
Lender.borrow();
}
}

and borrow for the minLoanSize of the lending pool(say as example [total pool size is 10 and minLoanSize is 1] )
3. When the malicious contract receives the loan token the fallback function again calls the borrow function of Lender contract,the loops goes until the pool gets empty and at last the collateral token(the minLoanSize) is send back to the lending pool. So the borrower gets the 9 loan token in change of only 1 collateral token and then the transactions end.

So the best mitigation is to use noreentrant modifier so that if anyone wants to call the function borrow again before the transaction complete they cannot.

Impact

By Re-enterancy anyone can empty the whole lending pool.

Tools Used

Manual Review

Recommendations

receive the collateral token first and after that transfer loan token.
or
use noReenter modifier.

  • do this function borrow(Borrow[] calldata borrows) public noReenter {...}

Support

FAQs

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