code-423n4 / 2024-02-wise-lending-findings

11 stars 8 forks source link

Permanent DoS of price oracle, upon updates to Chainlink's aggregators . #195

Closed c4-bot-4 closed 5 months ago

c4-bot-4 commented 6 months ago

Lines of code

https://github.com/code-423n4/2024-02-wise-lending/blob/main/contracts/WiseOracleHub/OracleHelper.sol#L94-L95

Vulnerability details

OracleHelper#_validateAnswer() gets the price from chainlink price feed which will be relatively recent because it is provided by the most reliable aggregator through the proxy, an then runs a validity check comparing the returned price with minAnswer and maxAnswer retrieved directly from the aggregator as the proxy contract does not expose those values. However chainlink updates the aggregators from time to time which can result in an update of minAnswer and maxAnswer values, and also the protocol doesn’t allow for an aggregator address update, as a result minAnswer and maxAnswer values will be deprecated and the price will no longer be in [minAnswer, maxAnswer] range so the call to the Oracle will always revert .

Proof of Concept

Consider the following scenario :

  1. the price of token is relatively high so Chainlink sets the minAnswer and maxAnswer according to that .
  2. a few days later the price of that token drops significantly .
  3. Chainlink deploys a new Aggregator with updated minAnswer and maxAnswer which reflects the price change .
  4. The _getChainlinkAnswer still gets the relatively recent price through the proxy .
  5. _compareMinMax gets the old values of minAnswer and maxAnswer from the deprecated aggregator when the price was high .
  6. Now the price returned from _getChainlinkAnswer will always be fewer than minAnswer and the call to OracleHub will always revert .

Impact

Bad debts cannot be settled because the paybackBadDebtForToken function in FeeManager relies on the oracle to determine the amount received by the user. The use of paybackBadDebtNoReward is highly unlikely as it lacks incentives . Also the FeeManager will no longer be able to claim fees because claimWiseFees calls _distributeIncentives that calls _gatherIncentives where the oracle price is also used . consequently, the protocol will become insolvent .

Tools Used

Manual Review

Recommended Mitigation Steps

use the updatedAt value from the latestRoundData() function to make sure that the latest answer is recent enough for you to use it instead .

function _getChainlinkAnswer(address _tokenAddress) internal view returns (uint256) {
        (, int256 answer,,uint256 updatedAt,) = priceFeed[_tokenAddress].latestRoundData();

                require(block.timestamp - updatedAt < PRICE_ORACLE_STALE_THRESHOLD, "Price round incomplete");

                return uint256(answer);
    }

Assessed type

DoS

GalloDaSballo commented 6 months ago

Reliant on admin mistake

c4-pre-sort commented 6 months ago

GalloDaSballo marked the issue as insufficient quality report

c4-pre-sort commented 5 months ago

GalloDaSballo marked the issue as remove high or low quality report

c4-pre-sort commented 5 months ago

GalloDaSballo marked the issue as duplicate of #30

c4-pre-sort commented 5 months ago

GalloDaSballo marked the issue as insufficient quality report

c4-judge commented 5 months ago

trust1995 changed the severity to QA (Quality Assurance)

c4-judge commented 5 months ago

trust1995 marked the issue as grade-c