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

Block Number Freezing

Summary

Submitting a high _block_number blocks future oracle updates

Vulnerability Details

vyper

assert self.last_block_number <= _block_number, "Outdated"

The contract checks that this _block_number is not older than the last recorded block number (self.last_block_number). This ensures updates are based on recent or future blocks relative to the last update. However, a problem arises if a prover submits a _block_number that is excessively high—far into the future. Subsequent updates with lower, more current block numbers would fail this check, effectively "freezing" the contract. The oracle would then be stuck with outdated data, unable to reflect new information.

`ScrvusdOracleV2.vy`’s `update_price` function:
```python
assert self.last_block_number <= _block_number, "Outdated"
self.last_block_number = _block_number # Stored without validation

The update_price function enforces that new updates must have a _block_number greater than the last recorded block (self.last_block_number).

code: https://github.com/CodeHawks-Contests/2025-03-curve/blob/198820f0c30d5080f75073243677ff716429dbfd/contracts/scrvusd/oracles/ScrvusdOracleV2.vy#L306-L308

Impact

  • Oracle Freezing: The oracle stops updating, returning stale prices.

Tools Used

anual code review.

Recommendations

Requiring the prover to submit the block timestamp (_block_timestamp) corresponding to _block_number.

  • Checking that this timestamp:

    • Is not in the future (i.e., <= block.timestamp).

    • Is not older than a maximum age (e.g., 30 minutes, or 1800 seconds).

# In update_price():
current_block: uint256 = BlockhashOracle(BLOCK_HASH_ORACLE).get_current_block_number()
assert _block_number <= current_block + 256, "Block too far in future"
assert current_block - _block_number <= 1800 // 12, "Block too old" # ~30 mins (assuming 12s/block)
self.last_block_number = _block_number
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.