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

Insufficient Block Number and Timestamp Validation

Summary

The IBlockHashRetain.vyi interface lacks crucial validation for block numbers and timestamps. This creates vulnerabilities around block finality and cross-chain compatibility.

Vulnerability Details

Current implementation lacks essential validations:

@external
def commit() -> uint256:
"""
@notice Commit (and apply) a block hash/state root.
@dev Same as `apply()` but saves committer
"""
# No block number validation
# No timestamp checks
...
@external
def apply() -> uint256:
"""
@notice Apply a block hash/state root.
"""
# Missing finality checks
# No cross-chain block time adjustments
...

Critical issues:

  1. No minimum block confirmation checks

  2. Missing block finality validation

  3. Absence of chain-specific block time adjustments

  4. No protection against future block numbers

  5. Lack of stale data prevention

Impact

  • Potential use of unfinalized block data

  • Cross-chain synchronization issues

  • Risk of stale data usage

  • Manipulation of block timing

  • Chain reorganization vulnerabilities

Tools Used

  • Manual Review

  • Cross-chain compatibility analysis

Recommendations

  1. Implement comprehensive block validation:

# Constants for different chains
BLOCK_TIME: constant(uint256) = 12 # seconds
MIN_CONFIRMATIONS: constant(uint256) = 12 # blocks
MAX_FUTURE_BLOCK: constant(uint256) = 10 # blocks
CHAIN_ID: constant(uint256) = 1 # mainnet
struct BlockValidation:
timestamp: uint256
confirmations: uint256
is_finalized: bool
@external
def validate_block(_block_number: uint256) -> bool:
"""
@notice Validate block number and finality
"""
assert _block_number <= block.number, "Future block"
assert _block_number > block.number - 256, "Block too old"
assert block.number - _block_number >= MIN_CONFIRMATIONS, "Insufficient confirmations"
# Chain-specific validations
if CHAIN_ID == 1: # Ethereum mainnet
assert block.number - _block_number >= 12, "Need more confirmations"
elif CHAIN_ID == 42161: # Arbitrum
assert block.number - _block_number >= 1, "Need confirmation"
return True
@external
def commit(_block_number: uint256) -> uint256:
"""
@notice Enhanced commit with validations
"""
assert self.validate_block(_block_number), "Invalid block"
# Calculate expected timestamp
expected_time: uint256 = block.timestamp - (
(block.number - _block_number) * BLOCK_TIME
)
# Store validation data
self.block_validations[_block_number] = BlockValidation({
timestamp: expected_time,
confirmations: block.number - _block_number,
is_finalized: True
})
return _block_number
  1. Add timestamp validation:

MAX_TIMESTAMP_DEVIATION: constant(uint256) = 300 # 5 minutes
@external
def validate_timestamp(_block_number: uint256) -> bool:
"""
@notice Validate block timestamp
"""
validation: BlockValidation = self.block_validations[_block_number]
# Check timestamp deviation
current_time: uint256 = block.timestamp
assert abs(current_time - validation.timestamp) <= MAX_TIMESTAMP_DEVIATION, "Time deviation too large"
return True
  1. Implement chain-specific adjustments:

struct ChainConfig:
block_time: uint256
min_confirmations: uint256
max_future_block: uint256
chain_configs: public(HashMap[uint256, ChainConfig])
@external
def initialize_chain_config():
"""
@notice Set chain-specific configurations
"""
self.chain_configs[1] = ChainConfig({ # Ethereum
block_time: 12,
min_confirmations: 12,
max_future_block: 10
})
self.chain_configs[42161] = ChainConfig({ # Arbitrum
block_time: 1,
min_confirmations: 1,
max_future_block: 100
})

These enhancements provide:

  • Chain-specific block validation

  • Protection against unfinalized data

  • Cross-chain compatibility

  • Timestamp deviation protection

  • Proper block finality checks

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.