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

Timestamp-Block Mismatch in ScrvusdVerifierV1

Summary

  • Timestamp and block header mismatches.

  • The issue arises when the verifyScrvusdByStateRoot function uses the last_profit_update (extracted as params[5]) as a timestamp without verifying that it aligns with the block's header timestamp from which the state root was obtained.

  • This misalignment can result in inconsistent and incorrect price calculations, potentially compromising the integrity of the protocol.

Vulnerability Details

The verifyScrvusdByStateRoot function retrieves last_profit_update (a timestamp) from the scrvUSD contract’s state but fails to validate whether this timestamp corresponds to the block from which the state root is derived.

If the state root is from an older block (e.g., due to delayed updates or stale data), the function may process inconsistent parameters that never coexisted in the same block. This mismatch can lead to incorrect price calculations for scrvUSD.

Example Scenario

  1. State Root Block: Block #100 (timestamp: 10:00 AM) is used to fetch scrvUSD’s parameters.

  2. last_profit_update: The state proof returns a value of 11:00 AM (from a newer block).

  3. Result: The oracle processes parameters (total_debt, total_idle, etc.) from block #100 alongside a last_profit_update timestamp that did not exist in that block. This inconsistency may cause the price to reflect unrealized profits or losses, corrupting the scrvUSD price feed.

Impact

  • Inaccurate Price Feeds: The oracle may compute a price based on a last_profit_update timestamp that occurred after the state root’s block, leading to invalid assumptions about scrvUSD’s financial state.

  • Operational Disruption: Wrong price updates can halt critical functions like profit distribution, causing a Denial-of-Service (DoS) on core protocol operations.

  • Reputation Damage: Repeated failures and inconsistencies may break user trust and damage the protocol’s reputation in the market.

Tools Used

Manual Code Review

Reference- https://github.com/CodeHawks-Contests/2025-03-curve/blob/198820f0c30d5080f75073243677ff716429dbfd/contracts/scrvusd/verifiers/ScrvusdVerifierV1.sol#L71-L80

Recommendations

Cross-Check Block Timestamp:

  • Extract the timestamp of the block associated with the state root and compare it against last_profit_update.

uint256 stateRootBlockTimestamp = IBlockHashOracle(BLOCK_HASH_ORACLE).getBlockTimestamp(_block_number);
require(
params[5] <= stateRootBlockTimestamp,
"last_profit_update exceeds state root block timestamp"
);
Updates

Lead Judging Commences

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

[invalid] finding-block-number-no-input-check

- 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

Support

FAQs

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