Core Contracts

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

Lack of NFT price freshness verification

Summary

Inside the getNFTPrice function in LendingPool.sol, there is no check on how recent the price is, which can lead to the borrower being under- or overcollateralized, potentially resulting in unnecessary liquidations or excessive borrowing

Vulnerability Details

Inside LendingPool, there are multiple functions that regularly check NFT price to verify users collateral value. The NFT price is checked in withdrawNFT and getUserCollateralValue, which is further called as part of borrow and calculateHealthFactor functions.

Prices of houses are updated from the external offchain APIs through RAACHousePriceOracle.sol. The prices are fetched and checked inside getNFTPrice function below:

function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);
if (price == 0) revert InvalidNFTPrice();
return price;
}

We can see that the oracle returns price and the lastUpdateTimestamp; however, it does not check the freshness of the price (i.e., when the price was last updated) and directly returns the price. This oversight is dangerous, especially because it is used in the above written critical functions like borrow and withdrawNFT where the user's collateral value is calculated.

If the oracle, for any reason, fails to update the price, a situation could arise where the stale price is returned, which could be exploited to borrow more than allowed or to withdraw a certain NFT, leaving the user undercollateralized.

Although the RAAC official documentation states that the RAACHousePriceOracle only processes valid responses from authorized Chainlink nodes, this does not guarantee that any of the external (off-chain or on-chain) components (e.g., API calls) won't fail or that the price can't become stale.

Impact

Although this exploit may have Medium to Low likelihood of happening, it still has significant impact as the user's value of collateral is calculated directly based on NFT prices.

Tools Used

Manual Review

Recommendations

To address this vulnerability and ensure the reliability of price data used throughout the system, define some price freshness threshold and check the lastUpdateTimestamp against it.

function getNFTPrice(uint256 tokenId) public view returns (uint256) {
(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);
if (price == 0) revert InvalidNFTPrice();
if (lastUpdateTimestamp > PRICE_THRESHOLD) revert StalePrice();
return price;
}
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!