Open sherlock-admin4 opened 3 months ago
Escalate
Dependence upon the provided oracle implementation poses a significant risk to the protocol.
Users have the freedom to arbitrarily control the price feeds of dependent assets in lieu of either significant attack complexity or prohibitive cost.
Even slight price volatility over the course of the three minute validity period would provide ample opportunity for an attacker to amplify impact when warping repeatedly between observations - consequently, there would be increased likelihood for the regularity of multifaceted protocol exploits rooted in this manipulation.
In this regard, we request this issue should be regarded as high severity.
Escalate
Dependence upon the provided oracle implementation poses a significant risk to the protocol.
Users have the freedom to arbitrarily control the price feeds of dependent assets in lieu of either significant attack complexity or prohibitive cost.
Even slight price volatility over the course of the three minute validity period would provide ample opportunity for an attacker to amplify impact when warping repeatedly between observations - consequently, there would be increased likelihood for the regularity of multifaceted protocol exploits rooted in this manipulation.
In this regard, we request this issue should be regarded as high severity.
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Escalate
There is no impact. The team has decided to choose any price within the range (-3 to +1) minutes as valid at any given timestamp
Escalate
There is no impact. The team has decided to choose any price within the range (-3 to +1) minutes as valid at any given timestamp
You've created a valid escalation!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
@10xhash
So am I correct in understanding that you believe an attacker repeatedly warping the price oracle back and forth between two preferred observations within the same transaction does not pose a risk to the protocol?
Hey @10xhash! The core issue here is that the current logic allows someone to bring back old prices. It's true that prices which are at most 3 minutes old may be submitted, but that's not the main problem. The issue is that a more recent price can be replaced by an older one, with no limit on how many times this can happen, as long as the older price is within the last 3 minutes.
The problem arises when, for example, price X is submitted, followed by price Y. Anyone can bring back the older price X, even though price Y is more recent and up to date. This not only opens the door for back-and-forth switching between prices, as @cawfree described, but an attacker can arbitrarily choose older prices before the Y price.
Now, imagine that we are currently at 00:00:00
, and consider the following scenario. A stable price, P1, aggregated 2-3 seconds earlier, so around 23:59:58
, is set via the updatePrice()
function,.
However, within the last 3 minutes, there was a brief period of volatility in the market, leading to a sudden but quickly recovered drop. This kind of scenario happens often—many tokens can drop by 1-2% and regain their value in a matter of seconds. During this volatility, Redstone Oracle aggregated a bad price at, say, 23:57:21
.
Although the recent price, P1, has already been submitted and correctly updated in the protocol, anyone can currently bring back the sudden drop from 23:57:21
, leading to potential liquidations + arbitrage activities, as they can also bring the P1 back.
You may argue that this price at 23:57:21
could have been submitted anyway, but it was not. Allowing to bring it back and switch it with a a more current one *unlimited amount of times poses significant risks. This won't be possible if we did not allow older prices to be set. ( Here we refer to older, as older than the current one set )
Since this can lead to a significant loss of funds, this issue is valid. It should be upgraded to high severity, as per Sherlock's rules.
I've also submitted the same issue here, and it should be marked as HIGH severity and labeled as a duplicate as well. ( @cawfree has escalated it :) )
I agree with @cawfree escalation.
The ability to manipulate the Redstone Oracle by repeatedly submitting older prices within the 3-minute validity period poses a significant risk to the protocol.
The fact that an attacker can choose between different valid price points in the same transaction creates an opportunity for price manipulation, leading to potential liquidations and arbitrage exploitation.
Planning to accept @cawfree escalation and make this issue High.
Result: High Has Duplicates
The protocol team fixed this issue in the following PRs/commits: https://github.com/sentimentxyz/protocol-v2/pull/331
cawfree
High
Red Stone Oracle Can Time Travel
Summary
The
RedstoneCoreOracle
can be atomically manipulated repeatedly back and forth between different observations within the validity period to yield different price readings upon demand.Vulnerability Detail
The
RedstoneCoreOracle
requires callers to manually update and cache the oracle price via theupdatePrice
function:Although here we correctly consider the worst-case staleness for newly-submitted observation (and the inter-observation timestamps themselves are validated to be consistent between both readings), there are are no protections against repeatedly calling
updatePrice
using valid data during the result validity period (for example, two different observations which took place within the same validity period) - even if that data has been seen before.This means it is possible to call
updatePrice
with one valid observation, immediately call it with a second valid observation, and then update again to revert back to the original observation in an effort to manipulate price.Proof of Concept
This proof of concept is split into two sections - for quick verification, judges need only focus on the first part, whereas the second part provides instructions on how to recreate mock payloads locally.
Example Observations (default)
Sherlock.t.sol
) to theprotocol-v2/test
directory:Next, run
ARB_RPC_URL="arbitrum-archive-node-url" forge test --match-test "testSherlockRedstoneTimestampManipulation" --ffi -vv
to yield the following:This demonstrates that the oracle price can be manipulated arbitrarily, atomically.
Generating Observations
In order to validate the calldata in the provided proof of concept exploit is authentic, in addition to the previous steps, judges will need to perform the following:
minimal-foundry-repo
to the top-level of the contest repo.getRedstonePayload.js
so that we can control the timestamp that the signatures are validated at via CLI argument, instead of using the system clock (this ensures we can generate observations which match the fork block number in the test):minimal-foundry-repo
, you should be able to generate simulated observations at custom timestamps like so:Impact
The
RedstoneCoreOracle
can be arbitrarily and repeatedly warped between preferential timepoints that coexist within the validity period, and is therefore highly susceptible to price manipulation.An attacker may exploit volatility over a three minute period (i.e. a stepwise reduction or appreciation in relative asset value) and repeatedly trade between minima and maxima - for example, purchasing at a checkpoint of low valuation and selling at a checkpoint of higher valuation.
This manipulation can be performed atomically within a single transaction, and requires little complexity.
Code Snippet
https://github.com/sherlock-audit/2024-08-sentiment-v2/blob/25a0c8aeaddec273c5318540059165696591ecfb/protocol-v2/src/oracle/RedstoneOracle.sol#L48C5-L61C6
Tool used
Manual Review
Recommendation
Allow at least the
THREE_MINUTES
period to expire since the last update before accepting a new update; if an attempt is made during this period, then terminate execution silently without arevert
.Here's an example of this approach.