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

Incorrect Storage Slot Hashing Breaks Cross-Chain State Verification

Summary

The ScrvusdVerifierV2 contract incorrectly calculates storage slot keys for fixed storage variables by hashing them, leading to verification of incorrect state values across chains and potential manipulation of oracle data.

Vulnerability Details

In the _extractPeriodFromProof function of ScrvusdVerifierV2.sol, the code incorrectly calculates the storage slot key for the profit_max_unlock_time variable using keccak256(abi.encode(PERIOD_SLOT)):

Verifier.SlotValue memory slot = Verifier.extractSlotValueFromProof(
keccak256(abi.encode(PERIOD_SLOT)), // Incorrect - hashing a direct slot
account.storageRoot,
proofs[1].toList()
);

This approach is fundamentally incorrect for accessing direct state variables in Ethereum's storage model. The profit_max_unlock_time variable is a simple state variable stored at slot 37 in the scrvUSD contract. According to Ethereum's storage layout specifications:

  1. Simple state variables are stored directly at their assigned slots (0, 1, 2, etc.)

  2. The correct way to access a direct slot is using bytes32(uint256(PERIOD_SLOT))

  3. Hashing with keccak256 is only used for accessing elements in mappings or dynamic arrays

By using the hashed slot computation, the verifier retrieves data from an entirely unrelated storage location (the hash of 37) rather than slot 37 where the actual profit_max_unlock_time value is stored.

Impact

Impact: HIGH - The incorrect slot calculation breaks the fundamental cross-chain verification mechanism, causing the system to verify and use entirely incorrect data. This directly compromises the oracle's ability to accurately report the profit_max_unlock_time value, which determines how quickly profits are unlocked in the system.

Likelihood: CERTAIN - This is not a probabilistic issue but a deterministic one. The code as written absolutely retrieves data from the wrong storage location every time it executes.

Why Current Tests Pass

If the off-chain proof generator and on-chain verifier both assume the incorrect hashed slot, they can produce matching proofs.

  • This self-consistent “lie” means tests pass without actually verifying the real on-chain state.

POC

  1. The scrvUSD contract on Ethereum has profit_max_unlock_time set to 604800 (7 days) at storage slot 37

  2. An off-chain prover generates a state proof for slot 37 (correctly)

  3. When the proof is submitted to verifyPeriodByStateRoot, the function calculates keccak256(abi.encode(37)), which results in a completely different storage location

  4. The function attempts to verify the proof against this incorrect location, which either fails (best case) or succeeds with a different value (worse case)

  5. If the hashed location happens to contain some other value (like 0 or a very small number), the profit_max_unlock_time will be incorrectly verified and set to this arbitrary value

  6. This causes profits to unlock too quickly or too slowly, breaking the economic model of the protocol

The issue breaks the entire purpose of the cross-chain verification system, as it verifies the wrong value.

Recommendations

Replace the hashing of the slot with the direct slot access method. Specifically:

// Replace this:
Verifier.SlotValue memory slot = Verifier.extractSlotValueFromProof(
keccak256(abi.encode(PERIOD_SLOT)), // Incorrect
account.storageRoot,
proofs[1].toList()
);
// With this:
Verifier.SlotValue memory slot = Verifier.extractSlotValueFromProof(
bytes32(uint256(PERIOD_SLOT)), // Correct for direct state variables
account.storageRoot,
proofs[1].toList()
);

Additionally, ensure that the off-chain proof generation is also adjusted to create proofs for the direct slot, not the hashed slot.

Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
Assigned finding tags:

[invalid] finding-storage-key-compute-wrong

See primary comments in issue #23

Appeal created

johnlaw Submitter
5 months ago
johnlaw Submitter
5 months ago
0xnevi Lead Judge
5 months ago
0xnevi Lead Judge
5 months ago
0xnevi Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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