This repository has been archived by the owner on Apr 28, 2024. It is now read-only.
roguereddwarf - Oracle.sol: manipulation via increasing Uniswap V3 pool observationCardinality #40
Labels
High
A valid High severity issue
Reward
A payout will be made for this issue
Sponsor Confirmed
The sponsor acknowledged this issue is valid
Will Fix
The sponsor confirmed this issue will be fixed
roguereddwarf
high
Oracle.sol: manipulation via increasing Uniswap V3 pool observationCardinality
Summary
This issue deals with how the
Oracle.consult
function can be provided with a maliciousseed
such as to return wrong results.This is a complex issue that requires multiple steps to be executed in order to set up and execute the attack.
In depth knowledge of the UniswapV3
observationCardinality
concept is needed as well as a wholesome understanding of the Aloe II protocol.This issue can occur as a result of an intentional attack but also as part of regular operation without attention to attack the protocol (even though unlikely).
The corrupted data that the
Oracle.consult
function provides as a result of this issue is used upstream by theVolatilityOracle
.The attack path is quite involved. However by exploiting this issue, the TWAP price can be manipulated as well as implied volatility (IV) and the probe prices.
Vulnerability Detail
The
Oracle.consult
function takes auint40 seed
parameter and can be used in either of two ways:Oracle.observe
function to get the observationsThe code for Aloe's
Oracle.observe
function is adapted from Uniswap V3's Oracle library.To understand this issue it is necessary to understand Uniswap V3's
observationCardinality
concept.A deep dive can be found here.
In short, it is a circular array of variable size. The size of the array can be increased by ANYONE via calling
Pool.increaseObservationCardinalityNext
.The Uniswap V3
Oracle.write
function will then take care of actually expanding the array once the current index has reached the end of the array.As can be seen in this function, uninitialized entries in the array have their timestamp set to
1
.And all other values in the observation struct (array element) are set to zero:
Here's an example for a simplified array to illustrate how the Aloe
Oracle.observe
function might read an invalid value:Here is the section of the
Oracle.observe
function where the invalid element is used to calculate the result.By updating the observations (e.g. swaps in the Uniswap pool), an attacker can influence the value that is written on the left of the array, i.e. he can arrange for a scenario such that he can make the Aloe
Oracle
read a wrong value.Upstream this causes the Aloe
Oracle
to continue calculation withtickCumulatives
andsecondsPerLiquidityCumulativeX128s
haing a corrupted value. EithersecondsPerLiquidityCumulativeX128s[0]
,tickCumulatives[0]
ANDsecondsPerLiquidityCumulativeX128s[1]
,tickCumulatives[1]
or onlysecondsPerLiquidityCumulativeX128s[0]
,tickCumulatives[0]
are assigned invalid values (depending on what the timestamp on the left of the array is).Impact
The corrupted values are then used in the further calculations in
Oracle.consult
which reports its results upstream toVolatilityOracle.update
andVolatilityOracle.consult
, making their way into the core application.The TWAP price can be inflated such that bad debt can be taken on due to inflated valuation of Uniswap V3 liqudity.
Besides that there are virtually endless possibilities for an attacker to exploit this scenario since the Oracle is at the very heart of the Aloe application and it's impossible to foresee all the permutations of values that a determined attacker may use.
E.g. the TWAP price is used for liquidations where an incorrect TWAP price can lead to profit.
If the protocol expects you to exchange 1 BTC for 10k USDC, then you end up with ~20k profit.
Since an attacker can make this scenario occur on purpose by updating the Uniswap observations (e.g. by executing swaps) and increasing observation cardinality, the severity of this finding is "High".
Code Snippet
Affected
Oracle.observe
function from Aloe II:https://github.com/aloelabs/aloe-ii/blob/c71e7b0cfdec830b1f054486dfe9d58ce407c7a4/core/src/libraries/Oracle.sol#L57-L81
Oracle
library from Uniswap V3 to see how to implement the necessary check for theinitialized
property:https://github.com/Uniswap/v3-core/blob/main/contracts/libraries/Oracle.sol
Tool used
Manual Review
Recommendation
The
Oracle.observe
function must not consider observations as valid that have not been initialized.This means the
initialized
field must be queried here and here and must be skipped over.The text was updated successfully, but these errors were encountered: