Core Contracts

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

Under-Collateralization Exploit: Attacker Drains Protocol Funds via Flawed WithdrawNFT function

Summary

A critical vulnerability in the withdrawNFT function allows attackers to systematically withdraw collateral while retaining excessive debt, leading to under-collateralized positions. By repeating this attack, malicious actors can drain the protocol’s liquidity pool entirely.

Vulnerability Details

The withdrawNFT function's flawed collateral check allows users to withdraw NFT collateral even when it leaves their position under-collateralized.

Root-cause: The formula incorrectly calculates the minimum required collateral as userDebt × liquidationThreshold

Insted we should be checking if (collateral - NFT value) * liquidationThreshold< userDebt and revert withdrawl if true.

function withdrawNFT(uint256 tokenId) external nonReentrant whenNotPaused {
.....
.....
//@audit wrong check.
if (collateralValue - nftValue < userDebt.percentMul(liquidationThreshold)) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}
....
...
}

example :

  • current User Debt: 75 ETH, collateral = 100ETH

  • Liquidation Threshold: 80% (0.8)

  • User wants to withdraw an NFT worth 20ETH.

  • Current Check: (collateral - NFT value) < userDebt * liquidationThreshold)
    collateralValue - nftValue = 100 ETH - 20 ETH = 80 ETH
    userDebt.percentMul(liquidationThreshold) = 75 ETH * 0.8 = 60 ETH

    if (80 ETH < 60 ETH) → false → withdrawal allowed

  • **Resulting Position After Withdrawal : **

    • Remaining Collateral: 80 ETH

    • Maximum Loan Allowed:
      80 ETH×0.8=64 ETH80 ETH×0.8=64 ETH

    • Existing Debt: 75 ETH (exceeds 64 ETH)

    • Position becomes Undercollateralized

Impact

  • Direct Fund Loss

  • Total Drain: Repeat attacks deplete the liquidity pool.

  • Systemic Collapse: Protocol becomes insolvent, unable to honor withdrawals.

Recommendations

Fix the Formula
Use the correct collateral check to enforce:

if ((collateralValue - nftValue).percentMul(liquidationThreshold) < userDebt) {
revert WithdrawalWouldLeaveUserUnderCollateralized();
}
Updates

Lead Judging Commences

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

Give us feedback!