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.
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
State Root Block: Block #100 (timestamp: 10:00 AM) is used to fetch scrvUSD’s parameters.
last_profit_update
: The state proof returns a value of 11:00 AM (from a newer block).
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.
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.
Manual Code Review
Cross-Check Block Timestamp:
Extract the timestamp of the block associated with the state root and compare it against last_profit_update
.
- 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
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.