The CoreChainlinkFeed contract returns the USD price for WBTC to be equal to the BTC-USD price feed. However this is not the same thing as a WBTC-USD price feed, and in the case that WBTC depegs from BTC, this oracle will not be properly valuing the WBTC in the WBTC-WETH LP collateral for the USDS stablecoin. This can lead to price manipulation of collateral (buy WBTC cheap -> create LP -> borrow more USDS than should be possible). This can break the entire stablecoin system.
function underlyingTokenValueInUSD( uint256 amountBTC, uint256 amountETH ) public view returns (uint256)
{
// Prices from the price feed have 18 decimals
uint256 btcPrice = priceAggregator.getPriceBTC();
uint256 ethPrice = priceAggregator.getPriceETH();
// Keep the 18 decimals from the price and remove the decimals from the token balance
uint256 btcValue = ( amountBTC * btcPrice ) / wbtcTenToTheDecimals;
uint256 ethValue = ( amountETH * ethPrice ) / wethTenToTheDecimals;
return btcValue + ethValue;
}
Although it is true that the PriceAggregator still has two other price sources if this occurs (Uniswap TWAP & SALTY spot price), the fundamental issue is that the price returned by the Chainlink Oracle for WBTC is incorrect. Additionally, it increases the probability of bricking the entire system (if Uniswap and SALTY prices deviate > 3%), and increases the probability of price manipulation due to the use of the SALTY spot price.
Tools Used
Manual review
Recommended Mitigation Steps
Both the WBTC-BTC and BTC-USD chainlink oracles should be used to get the WBTC-USD price. More specifically, this price should be calculated as (WBTC-BTC)*(BTC-USD) = WBTC-USD.
Lines of code
https://github.com/code-423n4/2024-01-salty/blob/main/src/price_feed/CoreChainlinkFeed.sol#L21 https://github.com/code-423n4/2024-01-salty/blob/main/src/price_feed/CoreChainlinkFeed.sol#L28-L60
Vulnerability details
Impact
The CoreChainlinkFeed contract returns the USD price for WBTC to be equal to the BTC-USD price feed. However this is not the same thing as a WBTC-USD price feed, and in the case that WBTC depegs from BTC, this oracle will not be properly valuing the WBTC in the WBTC-WETH LP collateral for the USDS stablecoin. This can lead to price manipulation of collateral (buy WBTC cheap -> create LP -> borrow more USDS than should be possible). This can break the entire stablecoin system.
Proof of Concept
As can be seen in CoreChainlinkFeed:latestChainlinkPrice, the logic for gathering the WBTC price involves querying the BTC-USD pricefeed.
This is ultimately referenced in a call to
priceAggregator.getPriceBTC()
in CollateralAndLiquidity:underlyingTokenValueInUSD, which is defined as follows:Although it is true that the PriceAggregator still has two other price sources if this occurs (Uniswap TWAP & SALTY spot price), the fundamental issue is that the price returned by the Chainlink Oracle for WBTC is incorrect. Additionally, it increases the probability of bricking the entire system (if Uniswap and SALTY prices deviate > 3%), and increases the probability of price manipulation due to the use of the SALTY spot price.
Tools Used
Manual review
Recommended Mitigation Steps
Both the WBTC-BTC and BTC-USD chainlink oracles should be used to get the WBTC-USD price. More specifically, this price should be calculated as
(WBTC-BTC)*(BTC-USD)
= WBTC-USD.Assessed type
Oracle