Core Contracts

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

Incorrect liquidation threshold application in borrow check allows excessive borrowing

Description

The LendingPool::borrow function incorrectly applies the liquidation threshold to the debt value instead of the collateral value when verifying loan-to-value ratios. This inversion enables borrowers to take out loans that exceed their collateralized limits, violating protocol safety parameters.

Proof of Concept
  1. User deposits NFT valued at 100 crvUSD (liquidationThreshold = 80%)

  2. Existing debt after borrowing: 90 crvUSD

  3. Protocol incorrectly calculates:

    • Faulty check: 100 ETH < (90 ETH * 80%) → 100 < 72 → false

    • Proper check: (100 ETH * 80%) < 90 ETH → 80 < 90 → true

  4. Borrow allowed despite exceeding 80 crvUSD collateralized limit

Relevant code snippet:

// LendingPool.sol
if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
revert NotEnoughCollateralToBorrow();
}

Test case to demonstrate vulnerability:

In LendingPool.test.js, add this test and run npx hardhat test --grep "allows borrowing beyond collateral limits"

// LendingPool.test.js
it("allows borrowing beyond collateral limits", async function () {
// Setup collateral
const tokenId = 1;
await raacNFT.connect(user1).approve(lendingPool.target, tokenId);
// Deposit collateral worth 100 crvUSD
await lendingPool.connect(user1).depositNFT(1);
// Attempt over-borrow (should only up to 80% of collateral but was successful)
const dangerousBorrow = ethers.parseEther("90");
await lendingPool.connect(user1).borrow(dangerousBorrow);
// Verify unsafe position
const healthFactor = await lendingPool.calculateHealthFactor(user1.address);
expect(healthFactor).to.be.lt(
await lendingPool.healthFactorLiquidationThreshold()
);
});
Impact

High severity - Allows creation of immediately undercollateralized positions, putting both borrower assets and protocol liquidity at risk. Violates core lending safety mechanisms.

Recommendation
  • Core fix: Apply liquidation threshold to collateral value instead of debt

- if (collateralValue < userTotalDebt.percentMul(liquidationThreshold)) {
+ if (collateralValue.percentMul(liquidationThreshold) < userTotalDebt) {
revert NotEnoughCollateralToBorrow();
}
  • Validation enhancement: Add pre/post checks for collateral health factor

// Before borrow
require(
calculateHealthFactor(collateralValue, newDebt) > safetyMargin,
"Insufficient collateral buffer"
);
// After borrow
require(
healthFactor > healthFactorLiquidationThreshold,
"Position becomes unsafe"
);
Updates

Lead Judging Commences

inallhonesty Lead Judge 3 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.