Rock Paper Scissors

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

Score Overflow in Long Games

Summary

The RockPaperScissors contract uses uint8 to store player scores (scoreA and scoreB). If the number of rounds (totalTurns) is set to a large number (e.g., > 255), and one player wins more than 255 rounds, an overflow occurs during the increment operation. While Solidity 0.8+ reverts on overflow, this causes the _determineWinner function to fail, halting the game and locking funds or tokens indefinitely.

Vulnerability Details

The vulnerable variables are declared as:

uint8 scoreA;
uint8 scoreB;

And are incremented as:

game.scoreA++;
// or
game.scoreB++;

If a player wins their 256th round, this operation causes an overflow:

  • In Solidity 0.8+, this triggers a revert due to automatic overflow checks.

  • The revert halts _determineWinner, preventing the game from progressing to the next round or finishing.

  • Players' funds or tokens are locked inside the contract.

There are no guards preventing games from being created with extremely high totalTurns, making this a viable griefing or denial-of-service vector.

Impact

  • Denial of service: The game becomes unrecoverable when overflow is triggered.

  • Locked funds/tokens: ETH or token rewards remain stuck in the contract.

  • Unfinishable game: The game can never transition to GameState.Finished, trapping players.

  • Potential griefing vector: An attacker can deliberately create games with high round counts to exploit this.

Tools Used

  • Manual code review

  • Solidity overflow rules (v0.8+)

  • Understanding of uint8 max value (255)

Recommendations

Change the data type of scoreA and scoreB from uint8 to uint16 or higher:

uint16 scoreA;
uint16 scoreB;

This provides much greater safety margins, supporting up to 65,535 wins per player.

Additionally, add a reasonable upper bound check for totalTurns during game creation:

require(_totalTurns <= 255, "Too many turns - would overflow scores");

This ensures that the number of rounds remains within the safe scoring range if keeping uint8, or adapt it based on the new data type’s max.

Updates

Appeal created

m3dython Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational

Code suggestions or observations that do not pose a direct security risk.

Support

FAQs

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