A critical vulnerability has been identified in the scrvUSD Oracle contract that could result in the incorrect calculation of smoothed asset prices. The vulnerability stems from an unsafe subtraction operation used to implement price bounding logic, which can lead to unintended behavior when prices fall significantly. This could potentially disrupt the price oracle's functionality and impact any dependent protocols that rely on this price feed for financial calculations.
The vulnerability exists in the _smoothed_price
function, which serves as the core mechanism responsible for limiting price volatility by smoothing price updates. This function is designed to restrict price changes to a maximum rate determined by the max_price_increment
parameter.
The flawed implementation uses the Vyper unsafe_sub
operation in a conditional check that determines whether a price change should be bounded:
The critical issue occurs in the line:
The function attempts to check if the absolute difference between raw_price
and last_price
exceeds max_change
. However, when raw_price
is significantly less than last_price
(indicating a sharp price decrease), the value of raw_price + max_change
can still be less than last_price
.
In such cases, the unsafe_sub
operation, which bypasses Vyper's standard underflow protection, will produce a very large number due to underflow. The resulting value will likely exceed 2 * max_change
, causing the condition to evaluate to true
incorrectly.
The consequence is that when prices are falling rapidly, the function may not properly limit the rate of decrease to max_change
, potentially allowing much larger price decreases than intended. For rising prices, the function operates correctly.
Consider the following scenario:
last_price
= 100000000000000000000 (100 with 18 decimals)
raw_price
= 50000000000000000000 (50 with 18 decimals, representing a 50% drop)
max_change
= 1000000000000000000 (1 with 18 decimals, representing a 1% allowed change)
Expected behavior:
The price should only drop by 1% to 99000000000000000000 (99)
Actual behavior:
raw_price + max_change
= 51000000000000000000 (51)
unsafe_sub(51000000000000000000, 100000000000000000000)
causes an underflow
In Vyper's unsafe_sub
, this would result in a very large number (2^256 - 49000000000000000000)
This large number is certainly greater than 2 * max_change
The condition evaluates to true
, but now the function incorrectly determines raw_price > last_price
is false
Returns last_price - max_change
= 99000000000000000000
While the output in this example looks correct (allowing a 1% drop), the actual logic is flawed and can produce unexpected results in different scenarios, especially with different maximum change calculations.
The vulnerability compromises the core functionality of price smoothing, which is essential for:
Preventing market manipulation
Protecting protocols that rely on the price feed
Ensuring stable operation of dependent DeFi systems
Flash Loan Attacks: An attacker could manipulate the underlying asset prices and exploit the behavior of the oracle during sharp price declines.
Liquidation Events: During market stress with significant price drops, the oracle may not properly smooth prices, potentially triggering cascading liquidations in lending protocols that rely on this price feed.
Arbitrage Opportunities: The incorrect price reporting could create arbitrage opportunities between protocols using this oracle and those using alternative price sources.
Replace the current implementation with a more robust approach that correctly handles both price increases and decreases:
If underflow occurs, it must have meant that `raw_price` has deviated from `last_price` by more than `max_change`, meaning it is correct to restrict the `last_price` increment to `max_change`
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.