The ScrvusdOracleV2
contract allows the same block number to be used in multiple calls to update_profit_max_unlock_time
and update_price
. This creates a replay attack vector, where an attacker can repeatedly submit old proofs to manipulate the oracle's state, even if newer, more accurate data is available.
In the ScrvusdOracleV2
contract, the update_profit_max_unlock_time
and update_price
functions include the following check:
This check is intended to allow for corrections in case of bad blockhash data. However, it also allows an attacker to repeatedly submit the same block number.
The access_control._check_role
mitigates the risk of unauthorized actors, but it does not prevent a malicious or compromised UNLOCK_TIME_VERIFIER
from exploiting this behavior.
A malicious or compromised verifier could:
Find a block with a favorable profit_max_unlock_time
value (e.g., unusually low value that increases price)
Then if the value changes to something less favorable, submit multiple updates with the same block number to manipulate the value
Manipulate price calculations and exploit price discrepancies in pools
In summary, an attacker can repeatedly call update_profit_max_unlock_time
with the same block_number
to manipulate the profit_max_unlock_time
value.
This vulnerability allows an attacker to:
Manipulate price calculations: By controlling the profit_max_unlock_time
, the attacker can influence the oracle's price calculations, potentially creating arbitrage opportunities or causing losses for liquidity providers.
Regulatory capture: An attacker could effectively "lock" the oracle to favorable historical values, preventing legitimate updates and profiting from the artificial price.
Cause financial harm: Exploiting price discrepancies in pools that rely on this oracle for pricing data can lead to significant financial losses.
Manual inspection, copilot, uv and moccasin.
Require strictly increasing block numbers. However, since the system has legitimate uses for same-block updates (fixing bad blockhash issues) consider fixes that balance security with functionality, such as an override flag with more security control which for example can allow same-block update if required and be cleared until it is explicitly reset again.
- See [here]([https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle)](https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle) on how it is used to verify storage variable - All state roots and proofs must be verified by the OOS `StateProofVerifier` inherited as `Verifier` (where the price values and params are extracted), so there is no proof that manipulating timestamp/inputs can affect a price update - It is assumed that the OOS prover will provide accurate data and the OOS verifier will verify the prices/max unlock time to be within an appropriate bound/values - There is a account existance check in L96 of `ScrvusdVerifierV1.sol`, in which the params for price updates are extracted from
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.