Core Contracts

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

Missing staleness check in NFT price oracle could lead to use of outdated prices

Summary

The LendingPool::getNFTPrice() function retrieves NFT prices from the oracle but does not validate the timestamp of the price update. This could lead to the use of stale prices in critical lending operations.

Vulnerability Details

The LendingPool::getNFTPrice() function retrieves both the price and last update timestamp from the oracle but only checks if the price is non-zero:

function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);
// @audit should check if the price is stale
if (price == 0) revert InvalidNFTPrice();
return price;
}

The function ignores the lastUpdateTimestamp, which could allow stale prices to be used in:

  1. Collateral valuation for borrowing

  2. Liquidation threshold calculations

  3. Health factor computations

Impact

The lack of staleness checks could lead to:

  1. Over-borrowing: If an NFT's market price has dropped significantly but the oracle price is stale, users could borrow more than their collateral's actual value warrants

  2. Delayed Liquidations: Unhealthy positions might not be liquidated in time if the system is using an outdated, higher price for the collateral

  3. Unfair Liquidations: Positions might be liquidated unnecessarily if the actual NFT price has increased but the system is using an outdated, lower price

The likelihood is HIGH as price updates can be delayed for various technical reasons, and prices can be highly volatile.
The impact is MEDIUM because while it could lead to incorrect lending positions, there could be other protocol safeguards that help mitigate the worst effects.

Tools Used

Manual review

Recommendations

Add a staleness threshold check in the LendingPool::getNFTPrice() function:

function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);
if (price == 0) revert InvalidNFTPrice();
+
+ // Ensure price is not stale (e.g., not older than 24 hours)
+ if (block.timestamp - lastUpdateTimestamp > 24 hours) {
+ revert StalePrice();
+ }
+
return price;
}

Consider also:

  1. Making the staleness threshold configurable by governance

  2. Adding events to track when stale prices are detected

  3. Implementing a fallback mechanism for handling stale prices (e.g., using a conservative price estimate)

Updates

Lead Judging Commences

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

LendingPool::getNFTPrice or getPrimeRate doesn't validate timestamp staleness despite claiming to, allowing users to exploit outdated collateral values during price drops

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

LendingPool::getNFTPrice or getPrimeRate doesn't validate timestamp staleness despite claiming to, allowing users to exploit outdated collateral values during price drops

Support

FAQs

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

Give us feedback!