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

Lack of Replay Protection

Description

Both verifier functions—verifyScrvusdByBlockHash and verifyScrvusdByStateRoot—process a provided state proof and forward the extracted parameters (including the block number and timestamp) to the oracle contracts without checking whether a proof from the same or an earlier block has already been processed. This means that the verifier does not enforce that proofs are only accepted once or that the block number is strictly increasing.

Workflow Explanation

  1. Proof Submission:
    A prover submits a state proof (RLP-encoded block header and storage proofs) corresponding to a particular Ethereum block number.

  2. Parameter Extraction:
    The verifier extracts parameters (including critical values such as total assets, supply, and balance) and the associated block number.

  3. Oracle Update Call:
    The verifier calls update_price (or update_profit_max_unlock_time in V2) on the oracle with these parameters.

  4. Replay Possibility:
    Since the verifier makes no check against a previously processed block number, a valid proof from an earlier block could be replayed—either accidentally or maliciously—to force an update based on stale data.

Attack Path

  • Step 1: An honest prover submits a valid proof for block N, which updates the oracle with correct, recent data.

  • Step 2: Later, an attacker replays the same proof (or another valid proof from block N) even though a more recent state exists.

  • Step 3: If the oracle does not enforce its own monotonicity or freshness check (or if the replay is timed to bypass such logic), the stale state could be used to update the oracle.

  • Impact:
    The oracle might be set to a stale price, potentially allowing an attacker to exploit price discrepancies—especially in a stableswap pool—through arbitrage.

Proof of Concept Outline


Assume block N is processed, and the oracle is updated with fresh parameters.


An attacker submits the same valid proof (for block N) after a later block (say, block N+M) has already been processed.

  • Result:
    Without replay protection, the verifier extracts the same old parameters, and the oracle updates with stale data, which may create a temporary mispricing exploitable via arbitrage.

Mitigation Recommendation

  • Add a check within the verifier to ensure that the incoming block number is strictly greater than the last processed block number.

  • Alternatively, rely on the oracle to perform this check—but having it in the verifier adds an extra layer of defense.

Updates

Lead Judging Commences

0xnevi Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope
Assigned finding tags:

[invalid] finding-replay-proof-lack-nonce

- All proof generated within `_proof_rlp` is generated via the off-chain prover, so there is no concrete proof that this proofs are non-unique. - All state roots and proofs must be verified by the OOS `StateProofVerifier` inherited as `Verifier`, so there is no proof that manipulating proofs can successfully pass a price update

Support

FAQs

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