Stratax Contracts

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

Missing Stale Price Validation

Author Revealed upon completion

Root + Impact

Description

  • In the StrataxOracle.sol contract, the price feeds are directly fetched from Chainlink without verifying whether the price data is up-to-date. The contract uses the latest price from Chainlink's latestRoundData() without ensuring that the data isn't stale.

  • The specific issue is that the contract assumes the price data is fresh, but it doesn't validate if the feed has been updated recently, potentially leading to the usage of outdated prices. This can result in incorrect collateral values, over-leveraging, or wrong liquidation calculations.

// Root cause in the codebase with @> marks to highlight the relevant section
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();
require(answer > 0, "Invalid price from oracle");
price = uint256(answer);
}

Risk

Likelihood:

  • The issue occurs every time the contract fetches a price from Chainlink without checking if the data is up-to-date.

  • This is especially problematic in cases of delays in price feed updates (e.g., network issues, downtime, or halts in the oracle feed).

Impact:

  • Incorrect collateral valuations: Using outdated prices may allow users to over-borrow, over-leverage, or undervalue collateral.

  • Risk of liquidation or insolvency: If the contract miscalculates collateral or loan-to-value ratios due to stale data, it can result in the liquidation of users' positions or system insolvency.

Proof of Concept

An example of how this could be exploited:

  1. The oracle feed stops updating after a market crash.

  2. The contract uses outdated price data, allowing a malicious user to over-borrow or manipulate their position.

  3. As a result, the user may withdraw more than they should or borrow against stale collateral values.

// Example exploit
contract Exploit {
StrataxOracle oracle;
IERC20 token;
constructor(address _oracle, address _token) {
oracle = StrataxOracle(_oracle);
token = IERC20(_token);
}
function attack() external {
// Using outdated price feeds for malicious borrow
uint256 price = oracle.getPrice(address(token));
// Further exploit logic
}
}

Recommended Mitigation

Add stale price validation to ensure the price data is not outdated before it’s used for calculations.

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,, uint256 updatedAt, uint80 answeredInRound) = priceFeed.latestRoundData();
+ require(answeredInRound >= roundId, "stale round");
+ require(block.timestamp - updatedAt < MAX_DELAY, "stale price");
require(answer > 0, "Invalid price from oracle");
price = uint256(answer);
}

Support

FAQs

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

Give us feedback!