Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: high
Likelihood: low

Missing Chainlink data freshness check leads to stale price usage

Author Revealed upon completion

Root + Impact

Description

  • The getPrice function retrieves the latest price from the Chainlink aggregator using latestRoundData.

  • However, it ignores the updatedAt and answeredInRound return values, failing to validate if the reported price is fresh and valid for the current block.

function getPrice(address _token) public view returns (uint256 price) {
// ...
AggregatorV3Interface priceFeed = AggregatorV3Interface(priceFeedAddress);
// @> Root cause: Only 'answer' is retrieved; 'updatedAt' and 'answeredInRound' are ignored.
(, int256 answer,,,) = priceFeed.latestRoundData();
require(answer > 0, "Invalid price from oracle");
price = uint256(answer);
}

Risk

Likelihood:

  • Chainlink oracles can stop updating

Impact:

  • The protocol calculates leverage and health factors based on outdated prices.

Proof of Concept

// Scenario:
// 1. ETH price is $2000. Oracle updates.
// 2. Market crashes, ETH is now $1000.
// 3. Oracle gets stuck or congested and hasn't updated for 5 hours.
// 4. User calls createLeveragedPosition().
// 5. getPrice() returns $2000 (stale) instead of reverting.
// 6. User borrows 2x what they should be allowed to.

Recommended Mitigation

function getPrice(address _token) public view returns (uint256 price) {
address priceFeedAddress = priceFeeds[_token];
require(priceFeedAddress != address(0), "Price feed not set for token");
AggregatorV3Interface priceFeed = AggregatorV3Interface(priceFeedAddress);
- (, int256 answer,,,) = priceFeed.latestRoundData();
+ (uint80 roundId, int256 answer, , uint256 updatedAt, uint80 answeredInRound) = priceFeed.latestRoundData();
+
require(answer > 0, "Invalid price from oracle");
+ require(updatedAt != 0, "Incomplete round");
+ require(answeredInRound >= roundId, "Stale price");
+ require(block.timestamp - updatedAt < 3600, "Price too old"); // Example 1 hour heartbeat
price = uint256(answer);
}

Support

FAQs

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

Give us feedback!