code-423n4 / 2022-01-yield-findings

1 stars 0 forks source link

Oracle might return stale or incorrect results (Cvx3CrvOracle.sol) #53

Closed code423n4 closed 2 years ago

code423n4 commented 2 years ago

Handle

ye0lde

Vulnerability details

Impact

Oracle might return stale or incorrect results (Cvx3CrvOracle.sol)

The _peek function in the contract Cvx3CrvOracle.sol fetches the daiPrice, usdcPrice, usdtPrice from a Chainlink aggregator using the latestRoundData function. If there is a problem with Chainlink starting a new round and finding consensus on the new value for the oracle (e.g. Chainlink nodes abandon the oracle, chain congestion, vulnerability/attacks on the chainlink system) consumers of this contract may continue using outdated stale or incorrect data.

Proof of Concept

https://github.com/code-423n4/2022-01-yield/blob/e946f40239b33812e54fafc700eb2298df1a2579/contracts/Cvx3CrvOracle.sol#L110-L127

        (, int256 daiPrice, , , ) = DAI.latestRoundData();
        (, int256 usdcPrice, , , ) = USDC.latestRoundData();
        (, int256 usdtPrice, , , ) = USDT.latestRoundData();

        require(
            daiPrice > 0 && usdcPrice > 0 && usdtPrice > 0,
            "Chainlink pricefeed reporting 0"
        );

Tools Used

Visual Studio Code, Remix

Recommended Mitigation Steps

I suggest the following changes including moving the calls to latestRoundData into a new function. Replace lines 120-127 with:

         (int256 daiPrice, int256 usdcPrice, int256 usdtPrice) = getPrices();

and add the getPrices function:

    function getPrices(
    ) private view returns (int256, int256, int256) {

        (uint80 daiRoundId,  int256 daiPrice,  , uint256 daiUpdateTime,  uint80 daiAnsweredInRound ) = DAI.latestRoundData();  
        (uint80 usdcRoundId, int256 usdcPrice, , uint256 usdcUpdateTime, uint80 usdcAnsweredInRound) = USDC.latestRoundData();
        (uint80 usdtRoundId, int256 usdtPrice, , uint256 usdtUpdateTime, uint80 usdtAnsweredInRound) = USDT.latestRoundData();

        require(
            daiPrice > 0 && usdcPrice > 0 && usdtPrice > 0,
            "Chainlink pricefeed reporting 0"
        );

        require(
            daiUpdateTime != 0 && usdcUpdateTime != 0 && usdtUpdateTime != 0,
            "Chainlink pricefeed reporting incomplete round"
        );

        require(
            daiAnsweredInRound >= daiRoundId && usdcAnsweredInRound >= usdcRoundId 
            && usdtAnsweredInRound >= usdtRoundId,
            "Chainlink pricefeed reporting stale price"
        );

        return (daiPrice, usdcPrice, usdtPrice);
    }
iamsahu commented 2 years ago

Duplicate of #136