DeFiLayer 1Layer 2
14,723 OP
View results
Submission Details
Severity: medium
Invalid

Lack of Timestamp Validation

Summary

The ScrvusdVerifier contracts demonstrate inadequate validation of timestamps used in oracle updates, potentially allowing manipulation of price data through inaccurate temporal references.

Vulnerability Details

In the verifyScrvusdByStateRoot function of ScrvusdVerifierV1, the contract uses a storage parameter as a timestamp surrogate without proper validation:

function verifyScrvusdByStateRoot(
uint256 _block_number,
bytes memory _proof_rlp
) external returns (uint256) {
bytes32 state_root = IBlockHashOracle(BLOCK_HASH_ORACLE).get_state_root(_block_number);
uint256[PARAM_CNT] memory params = _extractParametersFromProof(state_root, _proof_rlp);
// Use last_profit_update as the timestamp surrogate
return _updatePrice(params, params[5], _block_number);
}

The issue is that params[5] represents last_profit_update from the scrvUSD contract's storage, which is being used as the timestamp for the oracle update. This parameter is:

  1. Extracted directly from the provided proof without verification

  2. Not validated against any time boundaries

  3. Not checked for consistency with the block's actual timestamp

Additionally, the contract fails to ensure the timestamp is recent enough or not set in the future, nor does it compare this value with the actual timestamp from the block being referenced.

Impact

This vulnerability could allow an attacker to:

  1. Submit proofs with manipulated timestamp data

  2. Cause oracle updates to use incorrect temporal references

  3. Potentially influence price calculations that depend on time-weighted values

  4. Create opportunities for arbitrage by exploiting temporal inconsistencies in price data

The severity depends on how the Oracle contract uses this timestamp in its price calculations, but it represents a significant risk to the integrity of time-sensitive price data.

Recommendations

  1. Add Timestamp Boundary Checks:

// Add bounds checking for timestamp
require(params[5] <= block.timestamp, "Timestamp in future");
require(block.timestamp - params[5] <= MAX_TIMESTAMP_AGE, "Timestamp too old");
  1. Use Block Header Timestamp When Available:

    • In the verifyScrvusdByBlockHash function, the block header timestamp is available and should be preferred over storage parameters

  2. Cross-validate Time Parameters:

    • Compare timestamp with other temporal indicators (block number, etc.)

    • Implement consistency checks between multiple time-related parameters

  3. Time Window Requirements:

    • Define explicit time windows during which updates are valid

    • Reject updates with timestamps outside acceptable ranges

By implementing these recommendations, the contract would significantly reduce the risk of timestamp manipulation and improve the temporal integrity of the oracle system.

Updates

Lead Judging Commences

0xnevi Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

[invalid] finding-missing-proof-content-validation

- 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

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.