Rock Paper Scissors

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

Incorrect Enumeration Default Value in GameState Enum

Summary

The RockPaperScissors smart contract contains a vulnerability in the definition of the GameState enum. The enum does not include a proper default value (None/Uninitialized) as its first entry (index 0). Instead, GameState.Created is positioned as the first entry, which causes newly uninitialized storage variables of type GameState to automatically receive the value GameState.Created. This could lead to incorrect state management and potential security issues.

Vulnerability Details

In Solidity, enums are represented as unsigned integers, with the first defined value automatically assigned the value 0. When a storage variable of an enum type is declared without explicit initialization, it defaults to the first value in the enum (index 0).

The current GameState enum definition is:

enum GameState {
Created,
Committed,
Revealed,
Finished,
Cancelled
}

In this implementation, GameState.Created has value 0, meaning any uninitialized GameState variable will automatically be in the "Created" state. This is problematic because:

  1. Uninitiated game state variables automatically appear in a valid "Created" state

  2. The contract explicitly sets game.state = GameState.Created in the game creation functions, which is redundant and wastes gas

  3. There's no way to distinguish between a properly created game and an uninitialized game entry

Looking through the contract, I observed the issue when new games are created:

function createGameWithEth(uint256 _totalTurns, uint256 _timeoutInterval) external payable returns (uint256) {
// ... validation logic ...
uint256 gameId = gameCounter++;
Game storage game = games[gameId];
// At this point, game.state is already GameState.Created (0)
// ... other initializations ...
game.state = GameState.Created; // Redundant assignment
// ...
}

Impact

  1. Logic Errors: Functions that check for game.state == GameState.Created could succeed for uninitialized or invalid game entries

  2. Gas Waste: Redundant assignments waste gas during game creation

  3. Potential Security Bypass: If a function only checks that a game's state is "Created" before allowing certain operations, it might allow operations on non-existent or invalid games

  4. Difficult Debugging: Makes it harder to identify issues where game state initialization was skipped

The bug could be exploited if there are any functions that rely solely on the game state being "Created" to authorize operations without checking other game properties.

Tools Used

  • Manual code review

  • Solidity understanding of enum implementation and default values

  • Analysis of state-dependent control flow within the contract

Recommendations

  1. Add a None/Uninitialized state as the first enum value:

enum GameState {
None, // Default uninitialized state (0)
Created, // Now has value 1
Committed,
Revealed,
Finished,
Cancelled
}
Updates

Appeal created

m3dython Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Gas Optimization

Support

FAQs

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