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

Insufficient Block Validation in Verifier Contracts

Summary

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.

Vulnerability Details

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:

function verifyScrvusdByBlockHash(
bytes memory _block_header_rlp,
bytes memory _proof_rlp
) external returns (uint256) {
Verifier.BlockHeader memory block_header = Verifier.parseBlockHeader(_block_header_rlp);
require(block_header.hash != bytes32(0), "Invalid blockhash");
require(
block_header.hash == IBlockHashOracle(BLOCK_HASH_ORACLE).get_block_hash(block_header.number),
"Blockhash mismatch"
);
// ... rest of the 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.

Impact

A malicious actor could:

  1. Submit a fake future block with crafted parameters to manipulate the scrvUSD price

  2. 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

Tools Used

Manual Review

Onchain Simulation

Recommendations

  • Add validation that the submitted block is not from the future:

function verifyScrvusdByBlockHash(...) ... {
...
// Add these checks
require(block_header.number <= block.number, "Future block");
require(block_header.timestamp <= block.timestamp, "Future timestamp");
require(block.number - block_header.number >= 15, "Insufficient confirmations");
...
}
  • In the verifyScrvusdByStateRoot method, validate that the timestamp (which is derived from the last_profit_update parameter) is reasonable:

require(params[5] <= block.timestamp, "Future timestamp");
require(params[5] + MAX_TIMESTAMP_DELAY >= block.timestamp, "Timestamp too old");
Updates

Lead Judging Commences

0xnevi Lead Judge 5 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.