Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

No Commit Deadline Tracked

Vulnerability Details

The contract does not enforce a deadline for the commit phase in any game turn. This means players can indefinitely delay the game by simply refusing to commit their moves. While a deadline and timeout function exist for the reveal phase, there’s no such mechanism for the commit phase.

Bug Description

What's the Problem?

Games can get stuck forever in the commit phase if one player chooses not to act. Since the contract does not track a commit deadline or offer a timeout mechanism, it cannot recover from this situation, effectively locking the game and the staked tokens inside.

How It Happens: Step-by-Step

Game Setup

Two players initiate a game (e.g., a 3-turn game). Tokens or ETH are staked, and the first turn begins.

First Turn - Commit Phase
  • Player A commits their move.

  • Player B never commits.

The game is now stuck in the Committed state.
There is no deadline forcing Player B to act.
No one can progress or withdraw.

Later Turns (Even Worse)

Even if an earlier turn somehow completes:

  • The next turn also enters a Committed state.

  • A player can once again refuse to commit, repeating the stall indefinitely.

No Commit Deadline Tracked

The Game struct tracks a revealDeadline, but it lacks a commitDeadline:

struct Game {
// ...
uint256 revealDeadline; // ✅ Only for reveal phase
// No commitDeadline
}

No Timeout for Commit Phase

While a timeoutReveal() function exists to handle timeouts during the reveal phase, there is no equivalent for the commit phase.

Impact

  • ** Locked Funds**: ETH or tokens staked by both players get stuck in the contract.

  • ** Denial-of-Service**: Malicious players can harass opponents by freezing games on purpose.

  • ** Frustrated Users**: Legitimate players cannot complete or exit their games, leading to a poor experience.

Tools Used

  • Manual Review

Recommended Mitigation Steps

  1. Track a commitDeadline in the Game struct:

    uint256 commitDeadline;
  2. Set the commitDeadline whenever a new turn begins (or when a game is created).

  3. Add a timeoutCommit() function to allow the other player to forfeit the game if their opponent doesn't commit before the deadline.

  4. Ensure both revealDeadline and commitDeadline are strictly enforced with reasonable timeout windows.

Proof of Concept

  1. Player A and Player B start a 3-turn game.

  2. In the first turn:

    • Player A commits their move.

    • Player B refuses to commit.

  3. Since there is no commitDeadline, the game stays stuck forever in the Committed state.

  4. Neither player can cancel or reclaim their staked tokens.

  5. The game becomes unplayable.

This can be exploited repeatedly or unintentionally by disconnected or inactive players.

Updates

Appeal created

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Player B cannot cancel a game if Player A becomes unresponsive after Player B joins

Protocol does not provide a way for Player B to exit a game and reclaim their stake if Player A stops participating

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Player B cannot cancel a game if Player A becomes unresponsive after Player B joins

Protocol does not provide a way for Player B to exit a game and reclaim their stake if Player A stops participating

Support

FAQs

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