Core Contracts

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

Missing freshness check on house price data

Summary

The LendingPool uses a getNFTPrice function that is used to calculate a user's collateral value and their health factor, which is crucial to maintain risk within the protocol. The getNFTPrice function misses a freshness check on the return house price data, which can result in the usage of stale price data, causing risky debt positions in the protocol.

Vulnerability Details

The getNFTPrice function in LendingPool uses RAACHousePrices#getLatestPrice to determine an NFTs collateral value.
When the price is requested, the function also returns a timestamp, indicated when the price was updated.

This is important because the protocol needs up to date prices to properly asses the value of a user's collateral and allowing/disallowing debt positions accordingly.

Here's what getNFTPrice looks like:

function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);
if (price == 0) revert InvalidNFTPrice();
return price; // <-- no check on `lastUpdateTimestamp` before returning
}

While the function ensures that the returned price is valid, it doesn't actually consider the freshness of the price. Meaning, the lastUpdateTimestamp should be within a certain threshold, to consider the price "up to date".

Otherwise, the protocol risks to operate on stale prices which can lead to extremely risky debt positions as all collateral value and health factor calculations depend on this.

Impact

The queried NFT price is used in various places. Namely getUserCollateralValue, withdrawNFT, and inherently in borrow and calculateHealthFactor.
The functions are crucial for the protocol's health. Usage of stale prices can result in undercollateralized debt positions that, in the worst case, can't even be liquidated, which means users funds will be at risk.

Tools Used

Manual review.

Recommendations

There are a few things that can be done here:

  1. At the very least, perform a freshness check on the lastUpdateTimestamp. Revert if the price happens to be too old

  2. Reverting will prevent the protocol from functioning in case of stale prices, so it's better to have a fallback oracle to check the price on.

  3. Another option could be to only revert certain operations when the price is stale. For example, repaying the protocol should be allowed, regardless how old the price is, but taking out further debt should probably be prevent

It might also be worth exploring other incentive structures, such that other actors (bots) ensure the prices are updated on a regular basis.

Relevant links

Updates

Lead Judging Commences

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