A bug in the respective layer 0/1/2 network code that results in unintended smart contract behavior with no concrete funds at direct risk
Unbounded gas consumption in any in-scope contract function callable by external parties
Bug Description
In the challenger pipeline, each dispute game can reference a parent game and a child game. The parent-child relation is used to preserve dispute lineage and ensure a child cannot progress when its parent is already invalidated.
The off-chain challenger driver currently checks only the child game liveness (status, tee_prover, zk_prover) before submitting a challenge(), but does not pre-check parent validity. If the child remains IN_PROGRESS while the parent has already become invalid (CHALLENGER_WINS, blacklisted, or retired), on-chain challenge() deterministically reverts with InvalidParentGame.
After such revert, the driver keeps the entry in ReadyToSubmit and retries on every tick, but this path is not bounded by MAX_PROOF_RETRIES because retry_count only increments on proof job failures, not on submit failures.
An external actor who can create this parent/child state progression can force the challenger to repeatedly send reverted L1 challenge() transactions for the same game cause gas burn and delay dispute resolution.
Recommendation
Add a dedicated bounded submit retry mechanism (MAX_SUBMIT_RETRIES + per-entry submit_retry_count) for ReadyToSubmit, treat deterministic terminal reverts (for example InvalidParentGame) as drop conditions, and add a pre-submit parent-status validity check for DisputeIntent::Challenge consistent with on-chain parent validity rules.
Proof of Concept
steps:
Create or wait for a child game that remains scanner-actionable (IN_PROGRESS, tee_prover != 0, zk_prover == 0).
Make the parent game invalid before the child submission attempt (for example parent resolves CHALLENGER_WINS, or parent becomes blacklisted/retired).
Let challenger reach ReadyToSubmit; each challenge() attempt reverts deterministically with InvalidParentGame.
Observe the same game remains in retry loop beyond MAX_PROOF_RETRIES because submit failures do not increment retry_count.
patch:
run:
result:
The test demonstrates that submit retries continue even after more than MAX_PROOF_RETRIES, with the pending proof still in ReadyToSubmit and retry_count == 0.