Skip to content
This repository has been archived by the owner on Dec 17, 2023. It is now read-only.

santipu_ - Lack of checks to avoid stale prices from Chainlink oracle #444

Closed
sherlock-admin opened this issue Jun 11, 2023 · 0 comments
Closed
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Medium A valid Medium severity issue Reward A payout will be made for this issue

Comments

@sherlock-admin
Copy link
Contributor

sherlock-admin commented Jun 11, 2023

santipu_

medium

Lack of checks to avoid stale prices from Chainlink oracle

Summary

getPriceFromChainlink function is not checking the returned values of Chainlink Registry to ensure the prices are fresh and not stale.

Vulnerability Detail

When getting prices from Chainlink oracles, it's necessary to ensure the prices are fresh and not stale, and getPriceFromChainlink function from PriceOracle contract is not checking that.

/**
 * @notice Get price from Chainlink.
 * @param base The base asset
 * @param quote The quote asset
 * @return The price
 */
function getPriceFromChainlink(address base, address quote) internal view returns (uint256) {
    (, int256 price,,,) = registry.latestRoundData(base, quote);
    require(price > 0, "invalid price"); // @audit No checks for stale prices

    // Extend the decimals to 1e18.
    return uint256(price) * 10 ** (18 - uint256(registry.decimals(base, quote)));
}

Every Chainlink price feed has a different heartbeat, meaning it has to be updated every x amount of seconds depending on the feed, here some examples:

image

When getting prices from feeds, we have to ensure that the answer given by the oracle is fresh, meaning the answer given hasn't been updated more than a certain time ago. For ETH/USD oracle, the heartbeat is of 3600 seconds, meaning the oracle must be updated at least every 1 hour.

Related reports:

Impact

If the Chainlink oracle is returning stale prices, the protocol will use the wrong values to make decisions so it could lead to false liquidations or over-borrowing.

Code Snippet

https://github.com/sherlock-audit/2023-05-ironbank/blob/main/ib-v2/src/protocol/oracle/PriceOracle.sol#L60-L72

Tool used

Manual Review

Recommendation

It's recommended to check updatedAt value returned from Chainlink against some maxDelayTime value set in the contract depending of the feed used.

Example:

    function getPriceFromChainlink(address base, address quote) internal view returns (uint256) {
        (, int256 price,, uint256 updatedAt,) = registry.latestRoundData(base, quote);
        require(price > 0, "invalid price");
+       if(updatedAt < block.timestamp - maxDelayTime) revert(); // @audit Ensuring fresh prices

        // Extend the decimals to 1e18.
        return uint256(price) * 10 ** (18 - uint256(registry.decimals(base, quote)));
    }

Duplicate of #9

@github-actions github-actions bot added Medium A valid Medium severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Jun 19, 2023
@sherlock-admin sherlock-admin added Non-Reward This issue will not receive a payout and removed Medium A valid Medium severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label labels Jun 25, 2023
@sherlock-admin2 sherlock-admin2 added Medium A valid Medium severity issue Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Reward A payout will be made for this issue and removed Non-Reward This issue will not receive a payout labels Jul 19, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Duplicate A valid issue that is a duplicate of an issue with `Has Duplicates` label Medium A valid Medium severity issue Reward A payout will be made for this issue
Projects
None yet
Development

No branches or pull requests

2 participants