Core Contracts

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

Stale price vulnerability in getNFTPrice() due to missing timestamp validation and global update timestamp

Summary

The getNFTPrice() function claims to check for stale prices in its documentation but fails to implement any staleness checks.

Additionally, the oracle design uses a global lastUpdateTimestamp instead of per-token timestamps, which could lead to price manipulation and incorrect pricing for NFTs.

Vulnerability Details

Two critical issues exist:

1. Missing Staleness Check:

```solidity

function getNFTPrice(uint256 tokenId) public view returns (uint256) {

(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);

if (price == 0) revert InvalidNFTPrice();

return price; // @audit: lastUpdateTimestamp is never checked

}

```

2. Global Update Timestamp Design Flaw:

```solidity

contract RAACHousePrices is Ownable {

mapping(uint256 => uint256) public tokenToHousePrice;

uint256 public lastUpdateTimestamp; // @audit: global timestamp for all tokens

// ...

}

```

## Proof of Concept

1. Token A's price is updated at timestamp 100

2. Token B hasn't been updated since timestamp 50

3. When querying Token B's price, the system will return timestamp 100 (the global timestamp)

4. This makes Token B's stale price appear fresh, potentially leading to incorrect valuations // TODO: correct in context of valuations

Impact

High severity.

The vulnerability could lead to:

- Usage of stale or outdated price data for NFT transactions

- Potential price manipulation through outdated data

- Financial losses for users relying on incorrect pricing data

- One token update could make other tokens appear fresh when they're stale

Tools Used

VScode

Recommendations

1. Implement proper staleness checks:

```solidity

function getNFTPrice(uint256 tokenId) public view returns (uint256) {

(uint256 price, uint256 lastUpdateTimestamp) = priceOracle.getLatestPrice(tokenId);

if (price == 0) revert InvalidNFTPrice();

// Add staleness check

uint256 stalePriceThreshold = 24 hours;

if (block.timestamp - lastUpdateTimestamp > stalePriceThreshold) {

revert StalePriceData();

}

return price;

}

```

2. Modify the oracle to track per-token timestamps:

```solidity

contract RAACHousePrices is Ownable {

mapping(uint256 => uint256) public tokenToHousePrice;

mapping(uint256 => uint256) public tokenToLastUpdateTimestamp; // Per-token timestamp

function updatePrice(uint256 tokenId, uint256 newPrice) external {

tokenToHousePrice[tokenId] = newPrice;

tokenToLastUpdateTimestamp[tokenId] = block.timestamp; // Update token-specific timestamp

emit PriceUpdated(tokenId, newPrice);

}

}

```

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.