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

Missing Verification of Block Number in Verifier - Leads to Potential Oracle Manipulation

Title

Missing Verification of Block Number in Verifier - Leads to Potential Oracle Manipulation

Summary

The verifyScrvusdByStateRoot function in the ScrvusdVerifierV1 contract allows arbitrary _block_number inputs. This enables attackers to use arbitrarily large or non-existent block numbers, exploiting the oracle fallback hash mechanism to manipulate prices.

Vulnerability Details

https://github.com/CodeHawks-Contests/2025-03-curve/blob/main/contracts/scrvusd/verifiers/ScrvusdVerifierV1.sol#L72

The _block_number input is not checked properly, allowing invalid or future block numbers.
Consequently, the BlockHashOracle could return a fallback hash for such blocks instead of reverting, which attackers attempt to exploit to acquire malicious proofs.

function verifyScrvusdByStateRoot(
>> uint256 _block_number,
bytes memory _proof_rlp
) external returns (uint256) {
bytes32 state_root = IBlockHashOracle(BLOCK_HASH_ORACLE).get_state_root(_block_number);
uint256[PARAM_CNT] memory params = _extractParametersFromProof(state_root, _proof_rlp);
// Use last_profit_update as the timestamp surrogate
return _updatePrice(params, params[5], _block_number);
}

An attacker may submit a future or non-existent block number to verifyScrvusdByStateRoot, which then BlockHashOracle returns a fallback hash for. Then he provides the proof tied to this hash with manipulated price parameters, which is "accepted" and used to occur incorrect price updates.

Impact

An attacker can distort oracle prices, leading to incorrect pricing and potential loss of fund over the related parties and protocols.

Recommendations

Properly check _block_number input, so that it falls within the valid range. It should be neither in the future nor way too old in the past. Also, it should belong to an existing block to be valid.

Updates

Lead Judging Commences

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