Steadefi

Steadefi
DeFiHardhatFoundryOracle
35,000 USDC
View results
Submission Details
Severity: low
Valid

`ChainlinkARBOracle` and `ChainlinkOracle` do not check for stale prices

Summary

_badChainlinkResponse() function in both the ChainlinkARBOracle and ChainlinkOracle contracts are missing the stale data check.

Vulnerability Details

None of the oracle calls check for stale prices, for example

(
uint80 _latestRoundId,
int256 _latestAnswer,
/* uint256 _startedAt */,
uint256 _latestTimestamp,
@> /* uint80 _answeredInRound */
) = AggregatorV3Interface(_feed).latestRoundData();
function _badChainlinkResponse(ChainlinkResponse memory response) internal view returns (bool) {
// Check for response call reverted
if (!response.success) { return true; }
// Check for an invalid roundId that is 0
if (response.roundId == 0) { return true; }
// Check for an invalid timeStamp that is 0, or in the future
if (response.timestamp == 0 || response.timestamp > block.timestamp) { return true; }
// Check for non-positive price
if (response.answer == 0) { return true; }
return false;
}

Impact

Oracle data feeds can return stale pricing data for a variety of reasons. If the returned pricing data is stale, the getChainlinkResponse function will execute with prices that don’t reflect the current pricing resulting in a potential loss of funds due to incorrect calculations.

Tools Used

Manual

Recommendations

Read the _answeredInRound parameter from the calls to latestRoundData() and consider implementing the following changes in both ChainlinkARBOracle and ChainlinkOracle contracts :

function _getChainlinkResponse :

(
uint80 _latestRoundId,
int256 _latestAnswer,
/* uint256 _startedAt */,
uint256 _latestTimestamp,
- /* uint80 _answeredInRound */
) = AggregatorV3Interface(_feed).latestRoundData();
(
uint80 _latestRoundId,
int256 _latestAnswer,
/* uint256 _startedAt */,
uint256 _latestTimestamp,
+ /* uint80 _answeredInRound */
) = AggregatorV3Interface(_feed).latestRoundData();

function _badChainlinkResponse :

function _badChainlinkResponse(ChainlinkResponse memory response) internal view returns (bool) {
// Check for response call reverted
if (!response.success) { return true; }
// Check for an invalid roundId that is 0
if (response.roundId == 0) { return true; }
// Check for an invalid timeStamp that is 0, or in the future
if (response.timestamp == 0 || response.timestamp > block.timestamp) { return true; }
// Check for non-positive price
if (response.answer == 0) { return true; }
// Check for stale price
+ if (response.answeredInRound >= response.roundId) { return true; }
return false;
}
Updates

Lead Judging Commences

hans Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

Chainlink oracle answer can be negative

Very low likelihood -> evaluate the severity to LOW

Support

FAQs

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