For the complete documentation index, see llms.txt. This page is also available as Markdown.

74600 sc low proof threshold logic bug permanently locks game bond

Submitted on Apr 23rd 2026 at 18:21:49 UTC by @magtentic for Audit Comp | Base Azul

  • Report ID: #74600

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/base/contracts/tree/v8.1.0/src/multiproof

  • Impacts:

    • Permanent freezing of funds in the bridge or in dispute game bonds with no available recovery path

Description

Brief/Intro

In AggregateVerifier, games with PROOF_THRESHOLD = 2 must receive two proofs before resolving. The first proof resets the finalization delay (from ∞ to 7 days) but without a second proof, the game can never satisfy resolve(). The bond then becomes irrecoverable, freezing ETH indefinitely.

Vulnerability Details

Upon initialization, expectedResolution is set to type(uint64).max.

        // Set expected resolution.
        expectedResolution = Timestamp.wrap(type(uint64).max);

When a valid proof is submitted (_proofVerifiedUpdate is called), proofCount increments to 1 and _decreaseExpectedResolution sets expectedResolution = block.timestamp + SLOW_FINALIZATION_DELAY (7 days).

Thus after the first proof, expectedResolution is finite (7 days). However, resolve() requires gameOver() and proofCount >= PROOF_THRESHOLD.

If no second proof arrives, proofCount < 2 and resolve() always reverts NotEnoughProofs().

Meanwhile, claimCredit() checks if expectedResolution != max and requires the game to have resolvedAt != 0.

Since resolvedAt remains 0 (game never resolves), claimCredit() also reverts. The 14-day fallback timeout is only reachable when expectedResolution == max, but here it was lowered, so that branch is skipped.

The net effect is a permanent deadlock: the game stays IN_PROGRESS, the bond is locked in DelayedWETH, and no child games can proceed.

Impact Details

An honest proposer who posts one proof will have their entire ETH bond effectively locked forever if the second proof is missing or too costly to obtain. This violates in-scope impacts (“Permanent freezing of funds in dispute game bonds”) and blocks all dependent games. The protocol cannot finalize this proposal nor refund the bond without an explicit fix.

References

AggregateVerifier

  • initializeWithInitData sets expectedResolution = max

  • _proofVerifiedUpdate lowers it to block.timestamp + delay

  • In resolve(), the code requires proofCount >= PROOF_THRESHOLD

  • In claimCredit(), if expectedResolution is not max, resolvedAt must be non-zero

Proof of Concept

Copy the below PoC to test/AggregateVerifierThresholdTwoBondLockTest .t.sol

Run the below to execute

Was this helpful?