The ScrvusdVerifierV1 and ScrvusdVerifierV2 contracts do not implement sufficient checks to prevent future block submissions or validate block timestamps, which could lead to oracle manipulation.
Both verifier contracts accept block headers or block numbers without validating that:
The block is not from the future
The block header timestamp is reasonable
The contracts accept block headers/numbers without verifying if the block is finalized (sufficiently old to prevent chain reorganizations). This allows potential use of recent blocks that might be reorganized, leading to stale or manipulated data.
The block header timestamp is reasonable
Block timestamps are used directly without checking if they are within a reasonable range (e.g., not in the future or excessively old). This could allow manipulation of time-sensitive price calculations.
For example, in the verifyScrvusdByBlockHash
function:
There's no validation that block_header.number
is not from the future or that the timestamp is reasonable.
the contracts don't add their own checks on the block number's validity (like ensuring it's not too recent) or the timestamp's validity (like being within an acceptable range). This could allow a malicious actor to use a block that's not yet finalized or use old timestamps to affect the price.
A malicious actor could:
Submit a fake future block with crafted parameters to manipulate the scrvUSD price
Submit a valid block hash but with a manipulated timestamp to affect pricing calculations, especially in the v1 and v2 price approximations that rely heavily on timestamps
Manual Review
Onchain Simulation
Add validation that the submitted block is not from the future:
In the verifyScrvusdByStateRoot
method, validate that the timestamp (which is derived from the last_profit_update parameter) is reasonable:
- Anything related to the output by the `BLOCK_HASH_ORACLE` is OOS per \[docs here]\(<https://github.com/CodeHawks-Contests/2025-03-curve?tab=readme-ov-file#blockhash-oracle>). - The PoC utilizes a mock `BLOCK_HASH_ORACLE`which is not representative of the one used by the protocol - Even when block hash returned is incorrect, the assumption is already explicitly made known in the docs, and the contract allows a subsequent update within the same block to update and correct prices - All state roots and proofs must be verified by the OOS `StateProofVerifier` inherited as `Verifier`, so there is no proof that manipulating block timestamp/block number/inputs can affect a price update - There seems to be a lot of confusion on the block hash check. The block hash check is a unique identifier of a block and has nothing to do with the state root. All value verifications is performed by the OOS Verifier contract as mentioned above
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.