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.
The vulnerable variables are declared as:
And are incremented as:
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.
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.
Manual code review
Solidity overflow rules (v0.8+)
Understanding of uint8
max value (255)
Change the data type of scoreA
and scoreB
from uint8
to uint16
or higher:
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:
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.
Code suggestions or observations that do not pose a direct security risk.
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.