Rock Paper Scissors

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

No Check That Both Players Have Joined Before Commit

Summary

https://github.com/CodeHawks-Contests/2025-04-rock-paper-scissors/blob/25cf9f29c3accd96a532e416eee6198808ba5271/src/RockPaperScissors.sol#L191

The commitMove() function allows a player to commit a move even if the opponent hasn’t joined the game yet. While there’s a check to ensure playerB exists when playerA commits, there is no check to ensure playerA exists when playerB commits. This results in potential game inconsistencies.

Vulnerability Details

In the commitMove() function, players are allowed to commit their move after game creation. However, the function does not strictly verify that both players (i.e., playerA and playerB) have joined the game before allowing a move to be committed.

The only partial validation is that playerB must not be address(0) if the caller is playerA. There is no symmetric check ensuring that playerA exists if playerB commits first, nor is there a strong guarantee that both players are indeed set before any commitment is accepted.

This opens the possibility for an incomplete or invalid game state to proceed to the commitment phase.

Impact

If a commitment is made before both players are present, it may result in:

A one-sided lock of a player’s move commitment without the ability to proceed.

Inconsistencies or vulnerabilities during the reveal or payout phase if assumptions about two-player presence are violated.

Potential griefing attacks, where one player commits and waits indefinitely, blocking refunds or resolution.

** POC

function commitMove(uint256 gameId, bytes32 moveHash) external {
Game storage game = games[gameId];
require(game.state == GameState.Created || game.state == GameState.Committed, "Game not active");
if (msg.sender == game.playerA) {
require(game.commitA == 0, "Already committed");
require(game.playerB != address(0), "Player B not joined"); // ✅ GOOD
game.commitA = moveHash;
} else if (msg.sender == game.playerB) {
require(game.commitB == 0, "Already committed");
// ❌ MISSING: require(game.playerA != address(0), "Player A not joined");
game.commitB = moveHash;
} else {
revert("Not a player");
}
game.state = GameState.Committed;
}

and commits before playerA is set, the game could proceed to a Committed state with only one player present — breaking assumptions in later logic.

Tools Used

Recommendations

Updates

Appeal created

m3dython Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
m3dython Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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