Stratax Contracts

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

StrataxOracle fails to validate Chainlink data freshness, risking stale price usage during unwinds

Root + Impact

Description

The Oracle should return the most recent and valid price data from Chainlink to ensure accurate collateral and debt calculations.

The getRoundData function retrieves the price from latestRoundData but ignores the updatedAt timestamp and answeredInRound ID, allowing the system to accept stale or frozen prices during oracle outages.

// src/StrataxOracle.sol
function getRoundData(address _token)
public
view
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
address priceFeedAddress = priceFeeds[_token];
require(priceFeedAddress != address(0), "Price feed not set for token");
AggregatorV3Interface priceFeed = AggregatorV3Interface(priceFeedAddress);
@> (roundId, answer, startedAt, updatedAt, answeredInRound) = priceFeed.latestRoundData();
}

Risk

Likelihood:

  • The Chainlink feed heartbeat passes without an update due to network congestion (L2 sequencer downtime) or node operator issues.

Impact:

  • Users are unable to unwind positions because stale prices cause the debt repayment calculation to mismatch reality, leading to reverts.

  • The protocol miscalculates position health, preventing necessary liquidations or allowing under-collateralized borrowing.

Proof of Concept

Add this test to test/StrataxPoC.t.sol:

function test_OracleAcceptsStalePrice() public {
// 1. Setup a mock feed that hasn't updated in 365 days
MockAggregator staleFeed = new MockAggregator(2000e8, block.timestamp - 365 days);
oracle.setPriceFeed(address(tokenA), address(staleFeed));
// 2. Call getRoundData
(,, uint256 retrievedUpdatedAt,,) = oracle.getRoundData(address(tokenA));
// 3. Assert that the stale data is returned without revert
assertEq(retrievedUpdatedAt, block.timestamp - 365 days);
// Vulnerability: Contract accepted 1 year old price
}

Recommended Mitigation

function getRoundData(address _token) ... {
// ... previous code
(roundId, answer, startedAt, updatedAt, answeredInRound) = priceFeed.latestRoundData();
+ require(answer > 0, "Invalid price");
+ require(updatedAt != 0, "Incomplete round");
+ require(answeredInRound >= roundId, "Stale round");
+ require(block.timestamp - updatedAt <= 86400, "Stale price"); // Configurable heartbeat
}
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!