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

A malicious lender can seize the loan several times using a reentrancy attack.

Summary

A malicious lender can call seizeLoan() as many times as he wants and charge more collaterals than expected.

Vulnerability Details

After a failed refinance auction, the lender can seize the loan using seizeLoan().

function seizeLoan(uint256[] calldata loanIds) public {
for (uint256 i = 0; i < loanIds.length; i++) {
uint256 loanId = loanIds[i];
// get the loan info
Loan memory loan = loans[loanId];
// validate the loan
if (loan.auctionStartTimestamp == type(uint256).max)
revert AuctionNotStarted();
if (
block.timestamp <
loan.auctionStartTimestamp + loan.auctionLength
) revert AuctionNotEnded();
// calculate the fee
uint256 govFee = (borrowerFee * loan.collateral) / 10000;
// transfer the protocol fee to governance
IERC20(loan.collateralToken).transfer(feeReceiver, govFee);
// transfer the collateral tokens from the contract to the lender
IERC20(loan.collateralToken).transfer( //@audit seize loan several times using reentrancy
loan.lender,
loan.collateral - govFee
);
bytes32 poolId = keccak256(
abi.encode(loan.lender, loan.loanToken, loan.collateralToken)
);
// update the pool outstanding loans
pools[poolId].outstandingLoans -= loan.debt;
...
}
}

And the lender can charge more collaterals from the contract like this.

  1. Alice knows the contract has 100 ERC777 tokens for other pools.

  2. She creates a pool with collateral = ERC777, loanToken = USDC and deposits 20000 USDC.

  3. Using other accounts like Alice1 and Alice2, she creates 2 loans. Alice1 borrows 10000 USDC by providing 100 ERC777 and Alice2 borrows 10000 USDC by providing 1 ERC777 from Alice's pool.

  4. After that, Alice starts an auction with Alice1's loan and calls seizeLoan() after the auction is failed.
    Then Alice receives 100 ERC777(assume govFee = 0) instead of 10000 USDC which is profitable for her.

  5. Inside the transfer hook, she calls seizeLoan() again and receives 100 ERC777 again for Alice2's loan(10000 USDC).

Totally, Alice gets 200 ERC777 after providing 20000 USDC.
Alice1 gets 10000 USDC by providing 100 ERC777.
Alice2 gets 10000 USDC by providing 1 ERC777.

So Alice group's total profit will be 99 ERC777.

Impact

A malicious lender can steal more collateral from the contract.

Tools Used

Manual Review

Recommendations

We should add a nonReentrant modifier to seizeLoan().

Support

FAQs

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