The ScrvusdOracleV2
contract contains a critical vulnerability where the _raw_price()
function can revert due to division by zero. This occurs when the effective total supply (calculated as total_supply - _unlocked_shares
) becomes zero. The vulnerability can be triggered in multiple ways, including direct parameter manipulation, specific timing of updates, or as a result of normal system operations under certain conditions. This vulnerability could lead to a full denial of service for the price oracle, potentially impacting the entire scrvUSD ecosystem.
In the _raw_price()
function, the price calculation performs an integer division without validating that the divisor is non-zero:
The _total_supply()
function calculates the effective total supply by subtracting unlocked shares from the total supply:
If _unlocked_shares
equals or exceeds total_supply
, the function will attempt to divide by zero, causing the transaction to revert.
The vulnerability can be triggered in the following scenarios:
Direct Parameter Manipulation: If an entity with the PRICE_PARAMETERS_VERIFIER
role sets total_supply
to zero.
Full Share Unlocking: When the vault has fully unlocked all shares (full_profit_unlock_date
is in the past) and the balance_of_self
equals the total_supply
.
Parameter Calculation Issues: Specific combinations of profit_unlocking_rate
, last_profit_update
, and time differences can lead to unlocked shares equaling or exceeding the total supply.
Smart Contract State Evolution: Natural system operation could lead to edge cases where the effective total supply becomes zero.
We tried a PoC (below) which confirmed that the vulnerability exists.
Here are the key test cases that demonstrated the issue:
Setting total_supply
directly to zero caused a revert.
Setting total_supply
equal to balance_of_self
with full_profit_unlock_date
in the past caused a revert due to effective total supply becoming zero.
Setting a very high profit_unlocking_rate
with a long period since last_profit_update
caused a revert due to calculation issues in total supply computation.
The division by zero vulnerability has several significant impacts:
Complete Oracle Failure: When triggered, the oracle becomes completely non-functional, unable to provide price data to dependent contracts.
System-Wide Disruption: As the price oracle is a critical component of the scrvUSD ecosystem, its failure could disrupt:
Stableswap pools using the oracle for price adjustments
Liquidation mechanisms dependent on accurate pricing
User transactions requiring price data
Financial Risks:
Potential de-pegging of scrvUSD due to price feed disruptions
Inability to execute timely liquidations of undercollateralized positions
Arbitrage opportunities arising from price discrepancies
Potential loss of funds for users unable to exit positions
Exploitability: While exploitation requires certain privileges or specific conditions, the impact could be substantial, especially if timed during market volatility or system stress.
The vulnerability was verified using:
Custom Python Test Scripts: To simulate various parameter configurations and edge cases.
Boa Framework: For interacting with the contract in a test environment.
Manual Code Review: To identify potential division by zero paths in the contract logic.
Input Validation: Add explicit checks to prevent division by zero:
Parameter Validation: Add checks in the update_price
function to validate inputs:
Bound Checking: Ensure unlocked shares never exceed total supply:
Fallback Mechanism: Implement a fallback price mechanism that can be used when the primary calculation fails.
Circuit Breaker: Add a circuit breaker pattern to allow for emergency intervention without complete system failure.
Enhanced Access Controls: Implement timelock delays and/or multi-signature requirements for sensitive parameter updates.
Event Monitoring: Add events for significant parameter changes and near-zero values to facilitate monitoring.
Formal Verification: Consider formal verification of critical math operations to ensure they cannot result in division by zero under any circumstances.
Note that `total_supply` and `profit_unlocking_rate` is initially set to 1 and 0 respectively when the `ScrvusdOracleV2.vy` is deployed 1. `total_supply` and `profit_unlocking_rate` is part of the price param updates within `update_price`, which must have gone through verification via the OOS `StateProofVerifier` contract, so there is no evidence that a 0 supply is allowed either via a 0 supply update or an extremely high `profit_unlocking_rate`. 2. Since price is retrieved via values retrived from the V3Vault, if there is no supply, there is arguably no price to be posted. As such, reverting is arguably the correct choice since a 0 price value is not expected from scrvUSD, which is a stable coin.
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.