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

[M-02] Lender#buyLoan - poolBalance can be deducted by the wrong loan leading to an incorrect poolBalances

Summary

The Lender#buyLoan function in the lending protocol potentially exposes a flaw in pool balance management. Due to a lack of proper validation and matching between loanId and poolId, malicious actors can misuse the function to deduct from an incorrect pool balance, leading to unintended alterations of poolBalances.

Vulnerability Details

In the provided buyLoan function, the connection between loanId and poolId is not explicitly validated.

Due to this gap:

  1. A user can call the function with a valid loanId but pair it with an unrelated poolId. Let's assume the lending token for the loanId is USDC, and the collateral token is DAI. The lending token for the poolId is WETH, and the collateral token is USDT.

  2. The function proceeds to compute various balances and fees based on the loanId but then applies them to the provided poolId.

  3. This leads to potentially deducting amounts from the wrong pool.

See below, where we're deducting the loan.debt directly with the current poolId poolBalance and outstandingLoans without any checks.

uint256 totalDebt = loan.debt + lenderInterest + protocolInterest;
if (pools[poolId].poolBalance < totalDebt) revert PoolTooSmall();
_updatePoolBalance(poolId, pools[poolId].poolBalance - totalDebt);
pools[poolId].outstandingLoans += totalDebt;

Impact

  • Unintended Pool Deductions: Malicious users can force deductions from pools that have no connection to the intended loan.

  • Financial Implications: Pools could end up with balances that don't reflect their actual lending and borrowing activity. This can erode trust in the platform and cause financial discrepancies.

Tools Used

Manual Review.

Recommendations

Explicit Validation: Introduce an explicit validation step to ensure that the provided poolId matches the intended loan. This could involve encoding loan and pool relationships more explicitly or adding checks that verify the connection between a loanId and poolId. We could make the same matching as the giveLoan function:

if (pool.loanToken != loan.loanToken) revert TokenMismatch();
if (pool.collateralToken != loan.collateralToken) revert TokenMismatch();

before we call _updatePoolBalance.

Support

FAQs

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