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

Gas Intensive Loop in Parameter Extraction

1. Summary

  • Severity: Medium

  • Category: Gas Optimization / DoS Risk

  • Impact: Potential transaction failure due to gas limits

  • Likelihood: Medium - depends on network congestion and gas prices


2. Affected Code

function _extractParametersFromProof(
bytes32 stateRoot,
bytes memory proofRlp
) internal view returns (uint256[PARAM_CNT] memory) {
// ...existing code...
for (uint256 i = 1; i < PROOF_CNT; i++) {
Verifier.SlotValue memory slot = Verifier.extractSlotValueFromProof(
keccak256(abi.encode(PARAM_SLOTS[i])),
account.storageRoot,
proofs[i].toList()
);
params[i - 1] = slot.value;
}
// ...existing code...
}
  • Contract: ScrvusdVerifierV1

  • Function: _extractParametersFromProof

  • Lines: 89-109


3. Vulnerability Details

Root Cause

  • Each loop iteration performs:

    • RLP decoding (toList())

    • keccak256 hashing

    • Merkle proof verification

    • Storage slot extraction

  • Gas costs increase with proof complexity

Attack Scenario

  1. Network congestion increases gas prices

  2. Complex proofs require more gas for verification

  3. Transaction hits block gas limit

  4. Price updates fail, causing oracle staleness


4. Proof of Concept (PoC)

contract ScrvusdVerifierTest is Test {
function testGasLimitDoS() public {
// Setup
ScrvusdVerifierV1 verifier = new ScrvusdVerifierV1(address(blockOracle), address(oracle));
// Create maximum size proofs
bytes[] memory proofs = new bytes[](PROOF_CNT);
for(uint i = 0; i < PROOF_CNT; i++) {
proofs[i] = generateMaxSizeProof(); // Helper function to generate large valid proofs
}
bytes memory rlpProofs = rlpEncode(proofs);
// Should revert with "out of gas"
vm.expectRevert();
verifier.verifyScrvusdByStateRoot(block.number, rlpProofs);
}
}

5. Recommended Fix

Proposed Solution

contract ScrvusdVerifierV1 {
// Pre-compute slot hashes
bytes32[PROOF_CNT] private immutable SLOT_HASHES;
constructor() {
for(uint i = 0; i < PROOF_CNT; i++) {
SLOT_HASHES[i] = keccak256(abi.encode(PARAM_SLOTS[i]));
}
}
function _extractParametersFromProof(
bytes32 stateRoot,
bytes memory proofRlp
) internal view returns (uint256[PARAM_CNT] memory) {
// ...existing code...
for (uint256 i = 1; i < PROOF_CNT; i++) {
Verifier.SlotValue memory slot = Verifier.extractSlotValueFromProof(
SLOT_HASHES[i],
account.storageRoot,
proofs[i].toList()
);
params[i - 1] = slot.value;
}
// ...existing code...
}
}

Alternative Mitigation Strategies

  • Split parameter verification into batches

  • Implement gas-optimized RLP decoding

  • Cache frequently accessed proof data


6. Severity Justification

  • Impact: Medium

    • Can prevent price updates

    • Temporary DoS condition

    • Recoverable with higher gas limits

  • Likelihood: Medium

    • Bounded loop (8 iterations)

    • Network congestion common

    • Complex proofs likely

Updates

Lead Judging Commences

0xnevi Lead Judge
3 months ago
0xnevi Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Too generic

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.