Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Severity: medium
Valid

Stale Oracle Prices Accepted Without Timestamp Validation

Description

The oracle should only return fresh, recently updated prices to ensure accurate position valuations and prevent liquidations based on outdated data. The getPrice() function fetches price data from Chainlink but only validates that the price is non-zero, ignoring the updatedAt timestamp that indicates when the price was last updated.

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(); // updatedAt ignored
require(answer > 0, "Invalid price from oracle");
price = uint256(answer);
}

Risk

Likelihood:

During network congestion or oracle downtime, Chainlink feeds can become stale for hours/days
Market crashes can trigger oracle pauses, leaving old prices active
This happens regularly during extreme volatility

Impact:

Users get liquidated based on outdated prices when their actual position is healthy
Protocol calculates incorrect leverage ratios using stale prices
Flash loan repayment calculations fail when swap prices differ from stale oracle prices
Loss of user funds through unfair liquidations

PoC

// Scenario: Oracle price is 3 days old
// 1. User opens 3x ETH position when ETH = $3000 (current price)
// 2. Oracle returns stale price of $2500 (from 3 days ago)
// 3. calculateOpenParams uses $2500, calculates wrong borrow amount
// 4. User gets less leverage than expected OR transaction fails
// 5. No one notices because getPrice() doesn't validate freshness

Recommended Mitigation

difffunction 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();
+ (, int256 answer,, uint256 updatedAt,) = priceFeed.latestRoundData();
require(answer > 0, "Invalid price from oracle");
+ require(block.timestamp - updatedAt <= 3600, "Stale price"); // 1 hour max
price = uint256(answer);
}
Updates

Lead Judging Commences

izuman Lead Judge 16 days ago
Submission Judgement Published
Validated
Assigned finding tags:

Price feed has no staleness check

StrataxOracle contract fails to check if the price is stale, which can mess up swap calculations.

Support

FAQs

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

Give us feedback!