code-423n4 / 2024-03-dittoeth-findings

0 stars 0 forks source link

Attacker can force the use of chainlinks instead of TWAP oracles #72

Open c4-bot-9 opened 3 months ago

c4-bot-9 commented 3 months ago

Lines of code

https://github.com/code-423n4/2024-03-dittoeth/blob/91faf46078bb6fe8ce9f55bcb717e5d2d302d22e/contracts/libraries/LibOracle.sol#L102-L106

Vulnerability details

Impact

When the price of a token changes significantly, if the TWAP is intentionally not used, an attacker can benefit from the price difference.

Proof of Concept

In LibOracle.baseOracleCircuitBreaker, if the cached price and the newly retrieved price from Chainlink are significantly different, the UniswapV3 TWAP oracle is used. If the WETH balance in the Uniswap pool is less than 100 ether, the TWAP is not used, and the price from Chainlink is used instead.

Attackers can manipulate the balance of the Uniswap pool using Uniswap's flashswap feature. In other words, attackers can intentionally disable TWAP.

function baseOracleCircuitBreaker(
    uint256 protocolPrice,
    uint80 roundId,
    int256 chainlinkPrice,
    uint256 timeStamp,
    uint256 chainlinkPriceInEth
) private view returns (uint256 _protocolPrice) {
    ...
    } else if (priceDeviation) {
        // Check valid twap price
@>      try IDiamond(payable(address(this))).estimateWETHInUSDC(C.UNISWAP_WETH_BASE_AMT, 30 minutes) returns (uint256 twapPrice)
        {
            ...
            // Save the price that is closest to saved oracle price
            if (chainlinkDiff <= twapDiff) {
                return chainlinkPriceInEth;
            } else {
                // Check valid twap liquidity
                IERC20 weth = IERC20(C.WETH);
                uint256 wethBal = weth.balanceOf(C.USDC_WETH);
@>              if (wethBal < 100 ether) {
@>                  return chainlinkPriceInEth;
                }
                return twapPriceInEth;
            }
        } catch {
            return chainlinkPriceInEth;
        }
    } else {
        return chainlinkPriceInEth;
    }
}

The Chainlink oracle updates slower than DEX. When the price of a token changes significantly, if the TWAP is intentionally not used, an attacker can benefit from the price difference.

Tools Used

Manual Review

Recommended Mitigation Steps

Check UniswapV3 flashswap in this way.

(, , , , , , bool unlocked) = pool.slot0();
require(unlocked, "UniswapV3 reentrancy");

Assessed type

Oracle

c4-pre-sort commented 3 months ago

raymondfam marked the issue as insufficient quality report

c4-pre-sort commented 3 months ago

raymondfam marked the issue as primary issue

raymondfam commented 3 months ago

This is meant more for black swan scenario where the delta is set at 50%. In practice, price diff between order price and oracle > chainlink threshold is capped at 0.5%.

hansfriese commented 3 months ago

The impact is low after paying a 0.3% flashswap fee. QA is appropriate.

c4-judge commented 3 months ago

hansfriese changed the severity to QA (Quality Assurance)

c4-judge commented 3 months ago

hansfriese marked the issue as grade-b