20,000 USDC
View results
Submission Details
Severity: high

Unchecked ERC20 transfers in `borrow()` allow attacker to borrow without collateral

Summary

The borrow() function in Lender contract performs couple of different ERC20 transfers. The return values of those transfers are not checked. Some tokens do not revert on transfer failure, but return false instead. The lack of return value check may allow the attacker to steal all the tokens from the pool without providing any collateral.

Vulnerability Details

The following three ERC20 transfers occur in the borrow() function:

  1. Transfer of loanToken from the contract to the feeReceiver (protocol fees)

  2. Transfer of loanToken from the contract to the msg.sender (loan)

  3. Transfer of collateralToken from the sender to the contract (collateral)

The return values of those calls are not checked. This is specially problematic with the 3rd transfer, as the function never confirms if the collateral transfer was really successful. If that transfer has failed, for example because the borrower does not own enough collateralToken to put a valid collateral, the borrower would still receive the loan, even though they have not provided any collateral.

The problematic unchecked transfer:
https://github.com/Cyfrin/2023-07-beedle/blob/658e046bda8b010a5b82d2d85e824f3823602d27/src/Lender.sol#L271-L275

Impact

The attacker may steal all the tokens from the pool by taking a loan without collateral. This requires the collateralToken of the pool not to revert on failure.

The unsafe ERC20 operations have been reported in the known issues section under low category, however this particular exploitation of them is a separate, high-risk issue.

Tools Used

Manual Review

Recommendations

Replace the transfer/transferFrom calls with the OpenZeppelin safeTransfer/safeTransferFrom.

Support

FAQs

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