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.
The following three ERC20 transfers occur in the borrow()
function:
Transfer of loanToken
from the contract to the feeReceiver
(protocol fees)
Transfer of loanToken
from the contract to the msg.sender
(loan)
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
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.
Manual Review
Replace the transfer
/transferFrom
calls with the OpenZeppelin safeTransfer
/safeTransferFrom
.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.