Rock Paper Scissors

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

No check for Zero Hash Commit

Summary

The Rock Paper Scissors contract uses bytes32(0) as both a sentinel value to check if a player has committed a move and as a potentially valid commit value. This creates ambiguity in the game state and opens up potential exploits.

Vulnerability Details

The contract uses bytes32(0) to check if a player has already committed:

if (game.currentTurn == 1 && game.commitA == bytes32(0) && game.commitB == bytes32(0)) {
// First turn logic...
}
// Later in the code:
if (msg.sender == game.playerA) {
require(game.commitA == bytes32(0), "Already committed");
game.commitA = _commitHash;
} else {
require(game.commitB == bytes32(0), "Already committed");
game.commitB = _commitHash;
}

The vulnerability exists because:

  1. The contract checks if a commit is bytes32(0) to determine if a player has committed

  2. But the contract does not prevent a player from committing the value bytes32(0)

  3. This creates confusion: does bytes32(0) mean "no commit" or a valid commit of zero?

A player could legitimately generate a commit hash that equals bytes32(0) if they found the right combination of move and salt. Although extremely unlikely, it's theoretically possible.

Impact

This vulnerability impacts the game in several ways:

  1. State Confusion: The contract uses bytes32(0) both as "no commit" and potentially as a valid commit

  2. Logic Errors: A player who commits bytes32(0) might have their commit treated as "not committed"

  3. Potential Game Manipulation: This confusion could be exploited to manipulate game state in certain edge cases

While difficult to exploit directly, this represents a fundamental flaw in state management and data integrity.

Tools Used

Manual code review

Recommendations

Add an explicit check to reject bytes32(0) as a valid commit value:

function commitMove(uint256 _gameId, bytes32 _commitHash) external {
require(_commitHash != bytes32(0), "Invalid commit hash");
Game storage game = games[_gameId];
// Rest of the function...
}

This ensures a clear distinction between "no commit" (represented by bytes32(0)) and valid commits (any non-zero value). This is a basic but important validation that maintains clean state management and prevents ambiguity.

Updates

Appeal created

m3dython Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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