createGameWithEth() and createGameWithToken() accept any odd uint256 as totalTurns.
Because each turn requires a commit → reveal → winner cycle that writes to storage and emits events, a sufficiently large totalTurns will push the cumulative gas required to finish the game above the block‑gas limit. Once this threshold is crossed the game can never reach the _finishGame() / _handleTie() paths, so:
players’ ETH bet or staked WinningToken is locked forever;
accrued protocol fees remain stuck;
storage slots stay occupied permanently (“state bloat”).
No admin or rescue function can revive the game because _determineWinner() is the only path that completes it.
Attacker calls createGameWithEth{value: 0.01 ETH}(2 147 483 647, 5 minutes) (largest 31‑bit odd number, for example).
A victim joins with the matching bet.
Both parties commit and reveal for a handful of turns, until gas per block is insufficient for _determineWinner() to loop through the remaining turns.
From that point on:
commitMove() reverts because state == GameState.Committed but deadline cannot progress;
timeoutReveal() reverts unless one side has already revealed;
_finishGame() is unreachable.
ETH / tokens and protocol fees are now irrecoverable.
Funds at risk: locked indefinitely (users cannot withdraw, admin cannot reclaim fees).
Permanent DoS: the game ID stays in Committed state forever; new rounds cannot be created with same gameId.
No mitigating controls: neither maximum gas‑per‑turn nor owner rescue.
Introduce a MAX_TURNS cap in the protocol
Code suggestions or observations that do not pose a direct security risk.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.