The Rock Paper Scissors contract contains a critical flaw in its timeout mechanism during multi-turn games. Once the first turn is completed, Player A can unfairly claim victory by utilizing the timeoutReveal
function in subsequent turns, even if Player B is winning the match. This occurs because the contract does not reset or update the reveal deadline appropriately when transitioning between turns and doesn't verify that both players have committed their moves in the current turn before allowing timeout claims.
In the current implementation, when a game transitions from one turn to the next, the contract fails to properly reset or adjust the revealDeadline
. This creates a situation where, in turns after the first one, the following exploit is possible:
Player A commits and reveals their move for the current turn
Player A waits for the revealDeadline
to pass without requiring Player B to commit their move
Player A calls timeoutReveal
, allowing them to claim victory unfairly
The core issue is in the timeoutReveal
function, which checks only the following conditions:
Then it determines the winner using logic that doesn't account for the current state of the game in a multi-turn scenario:
This means that a timeout in any turn leads to declaring an overall winner of the entire game, regardless of the score at that point.
This was successfully demonstrated in the testMultiTurnTimeout()
test by modifying it to remove Player B's commit in the second turn:
The test confirms that Player A successfully claims the entire pot, even though Player B was leading with a score of 1-0 after the first turn.
This vulnerability has a high impact as it:
Allows a player to unfairly win the entire game's pot regardless of the current score
Creates a disincentive for fair play, as the winning strategy becomes exploiting the timeout rather than actual gameplay
Undermines the game's integrity by allowing a player to win without their opponent having a chance to commit a move
The financial impact is significant as the winning player takes the entire pot (minus fees), resulting in the full loss of funds for the opponent.
Manual code review
Foundry tests for PoC
To address this vulnerability, several changes should be implemented:
Distinct Game States: Implement separate states for each phase of the game (waiting for commits, waiting for reveals) rather than using a single "Committed" state for multiple phases.
Reset Timeout Values: Properly reset the reveal deadline when transitioning to a new turn:
Require Both Players to Commit: Add a check in the revealMove
and timeoutReveal
functions to ensure both players have committed before allowing reveals or timeouts in each turn:
Add Turn Validation: Include the current turn number in commit and reveal operations to ensure players can't reuse commitments or reveals from previous turns.
timeoutReveal function incorrectly allows execution and game cancellation even when only one player has committed
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.