DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Missing roundId Validation in KeeperProxy::_check Function

Summary

The _check function is responsible for validating price data using Chainlink's latestRoundData(). However, it does not validate the roundId, which is crucial for ensuring data correctness, freshness, and integrity.

Without roundId validation, the function may process incomplete, stale, or manipulated price data, leading to incorrect price calculations and potential financial risks.

Vulnerability Details

function _check(address token, uint256 price) internal view {
// https://github.com/code-423n4/2021-06-tracer-findings/issues/145
(, int chainLinkPrice, , uint256 updatedAt, ) = AggregatorV2V3Interface(dataFeed[token]).latestRoundData();
// block.timestamp - updatedAt > priceFeedHeartbeatSeconds
require(updatedAt > block.timestamp - maxTimeWindow[token], "stale price feed");
uint256 decimals = 30 - IERC20Meta(token).decimals();
price = price / 10 ** (decimals - 8); // Chainlink price decimals is always 8.
require(
_absDiff(price, chainLinkPrice.toUint256()) * BPS / chainLinkPrice.toUint256() < priceDiffThreshold[token],
"price offset too big"
);
}

The function retrieves data using latestRoundData(), but it does not check the roundId. The function directly uses the returned chainLinkPrice without verifying the roundId. If Chainlink's oracle returns stale or incomplete data, the contract might still use the price, leading to incorrect calculations.

Impact

Using outdated price data if Chainlink has not updated recent prices.

Accepting incomplete rounds where the price feed might still be changing.

Positions open on wrong collateral prices which may cost major financial losses to the protocol.

Incorrect collateral valuation can cause under-collateralization.

Tools Used

Manual Review

Recommendations

To mitigate the risk, latestRoundData function returns the answeredInRound value among other returned values. Although this value is depreacated as mentioned in the docs but still this can be used to validate the roundId. Another way is to check the startedAt timestamp because each roundData has this prop. The implication should be like, startedAt should be greater than last startedAt this will ensure that price does not pertain to previous round and the price is fresh and udpated.

Updates

Lead Judging Commences

n0kto Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelihood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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

Give us feedback!