Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

LendingPool: Insufficient Collateral Check in Borrow Function

Summary

Name: Insufficient Collateral Check in Borrow Function in LendingPoolcontract
Class: Logic Error
Severity: High
Likelihood: Medium
Impact: High

Vulnerability Details

The borrow function incorrectly checks if collateralValue < userTotalDebt.percentMul(liquidationThreshold). This allows users to borrow amounts that exceed their collateral value when liquidationThreshold < 100%, violating the collateralization principle.

Vulnerable Code:

function borrow(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
...
uint256 userTotalDebt = user.scaledDebtBalance.rayMul(reserve.usageIndex) + amount;
// Flawed check:
@> if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}
...
}

Exploitation Scenarios:

Example 1: Overborrowing Against Collateral

  1. Attacker Actions:

    • Deposits an NFT valued at 100 ETH.

    • Borrows 125 crvUSD with liquidationThreshold = 80%.

  2. Check Bypass:

    • userTotalDebt = 125 crvUSD.

    • userTotalDebt.percentMul(80%) = 100 crvUSD.

    • collateralValue = 100 ETH → Check passes.

  3. Result:

  • Debt (125 crvUSD) exceeds collateral (100 ETH).

  • Protocol cannot recover debt if NFT value drops.

Example 2: Systemic Risk via Mass Exploitation

  1. Attacker Actions:

    • Creates multiple accounts.

    • Each account borrows up to collateralValue / liquidationThreshold.

  2. Result:

  • Protocol accumulates undercollateralized debt.

  • Liquidation fails during market downturns.

POC

// Test Transaction:
address user = 0x123...;
uint256 tokenId = 1;
uint256 nftPrice = 100e18; // 100 ETH
uint256 borrowAmount = 125e18; // 125 crvUSD
// 1. Set NFT price
priceOracle.setPrice(tokenId, nftPrice);
// 2. Deposit NFT
pool.depositNFT(tokenId);
// 3. Exploit: Borrow 125 crvUSD with 80% threshold
pool.borrow(borrowAmount); // Succeeds despite undercollateralization

Impact

Undercollateralized Debt: Loans exceed collateral value, leading to protocol insolvency.

Liquidation Failures: Collateral cannot cover debt during mass liquidations.

Protocol Instability: Risk of bank run if users lose confidence.

Tools Used

Recommendations

Fix the Collateral Check:

Replace the flawed condition with:

- if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
+ if (collateralValue < userTotalDebt.percentDiv(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}

Formula:

Example: For liquidationThreshold = 80%, collateral must be ≥ 125% of debt.

Add Documentation: Clarify that liquidationThreshold represents the minimum collateral-to-debt ratio.

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool::borrow as well as withdrawNFT() reverses collateralization check, comparing collateral < debt*0.8 instead of collateral*0.8 > debt, allowing 125% borrowing vs intended 80%

Support

FAQs

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