Skip to content

Latest commit

 

History

History
59 lines (41 loc) · 2.04 KB

002.md

File metadata and controls

59 lines (41 loc) · 2.04 KB

Exotic Navy Elephant

Medium

Chainlink Oracle returns stale price due to missing checks on heartbeat

Summary

Chainlink price feeds usually update the price of an asset once it deviates a certain percentage. For example the ETH/USD price feed updates on 0.5% change of price. If there is no change for 1 hour, the price feed updates again - this is called heartbeat: https://data.chain.link/feeds/ethereum/mainnet/eth-usd.

This was not implemented to prevent stale prices.

Root Cause

The implementation does not check for stale prices.

            (, int256 price_, , , ) = oracle.latestRoundData(); //@audit
            // If the token is ETH
            if (underlying == assetAddress[IBorrowing.AssetName.ETH]) {
                // Return Exchange rate as 1 and ETH price with 2 decimals
                return (1 ether, uint128((uint256(price_) / 1e6)));
            } else {
                (, uint128 ethPrice) = _price(assetAddress[IBorrowing.AssetName.ETH]);
                // Return Exchange rate and ETH price with 2 decimals
                return (uint128(uint256(price_)), ethPrice);
            }

https://github.com/sherlock-audit/2024-11-autonomint/blob/0d324e04d4c0ca306e1ae4d4c65f0cb9d681751b/Blockchain/Blockchian/contracts/oracles/MasterPriceOracle.sol#L83C1-L92C14

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

Outdated prices are returned providing inaccurate old prices to users.

PoC

No response

Mitigation

Introduce a new parameter that could be passed alongside the oracle which refers to the heartbeat of that oracle, so that updatedAt could be compared with that value. E.g

+    ( , int price, , uint256 updatedAt, ) = oracle.latestRoundData();
+     require(price > 0, "Invalid price");  
+     require(answeredInRound >= roundId, "Stale price data");
+    // Timestamp validation to ensure freshness  
+    require(block.timestamp - updatedAt <= MAX_DELAY, "Stale price data");   //MAX_DELAY specify for each address