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

Denial of Service (DoS) via Gas Limits: Unbounded Proof Size

Summary

The contract processes RLP-encoded proofs in _extractPeriodFromProof, and there is no limit on the size or complexity of the proof data. An attacker could submit a large, complex proof that exceeds the block gas limit, causing the transaction to revert and preventing legitimate updates.

Vulnerability Details

  • Description:
    The _extractPeriodFromProof function parses an RLP-encoded proof:

RLPReader.RLPItem[] memory proofs = proofRlp.toRlpItem().toList();
require(proofs.length == 2, "Invalid number of proofs");

While the function checks that the proof contains exactly 2 items, it does not restrict the size or complexity of the RLP data (e.g., deeply nested structures). The RLPReader and StateProofVerifier libraries process this data, and large inputs can consume excessive gas, potentially exceeding the Ethereum block gas limit (approximately 30 million gas as of March 2025).

  • Root Cause: Lack of an upper bound on the size of the _proof_rlp input, allowing arbitrarily large data to be processed.

  • Validation: Confirmed by:
    Reviewing the RLPReader library, which recursively processes RLP items, with gas costs proportional to the data size and complexity.
    Analyzing StateProofVerifier.extractSlotValueFromProof, which verifies Merkle proofs, with gas costs increasing with proof length.
    Recognizing that Ethereum’s block gas limit imposes a hard constraint, and unbounded inputs are a known DoS vector.

Impact

  • Severity:
    Medium

  • Description:
    Prevents legitimate updates to profit_max_unlock_time, potentially delaying oracle adjustments and affecting downstream systems. No direct financial loss occurs, but operational disruption could impact user trust and system reliability.
    Likelihood: Medium, as crafting a large proof requires some effort but is feasible for a motivated attacker with access to the public functions.

Tools Used

Manual Code Review: Analyzed proof parsing logic and gas consumption multiple times.

Recommendations

Proof Size Limit: Add a maximum size check for _proof_rlp in both verifyPeriodByBlockHash and verifyPeriodByStateRoot:

function verifyPeriodByBlockHash(bytes memory _block_header_rlp, bytes memory _proof_rlp) external returns (bool) {
require(_proof_rlp.length <= 512, "Proof too large"); // Adjust limit based on testing
// Existing logic
}
function verifyPeriodByStateRoot(uint256 _block_number, bytes memory _proof_rlp) external returns (bool) {
require(_proof_rlp.length <= 512, "Proof too large"); // Adjust limit based on testing
// Existing logic
}
Updates

Lead Judging Commences

0xnevi Lead Judge
6 months ago
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.