The RockPaperScissors contract fails to validate that game IDs exist before operating on them in nearly all game-related functions. This critical vulnerability allows calls to be made with non-existent game IDs, which can lead to unexpected behavior, silent failures, and in some cases security vulnerabilities due to operations on uninitialized structs.
Throughout the contract, multiple functions take a _gameId
parameter but never verify that this ID corresponds to an existing game before accessing the games[_gameId]
mapping. When a non-existent game ID is provided, the contract doesn't revert but instead operates on an empty/default struct, which can have various negative consequences.
Examples of vulnerable functions include:
commitMove
revealMove
timeoutReveal
Internal functions like _determineWinner
The vulnerability extends to view functions like canTimeoutReveal
and canTimeoutJoin
, which return information about potentially non-existent games.
Medium to high severity. The vulnerability creates multiple issues:
Silent Failures: Many operations may silently fail or produce incorrect results when operating on non-existent games.
Unpredictable Behavior: Functions could behave in unexpected ways when operating on default structs, potentially causing state confusion.
Gas Waste: Users might waste gas on transactions that perform meaningless operations on non-existent games.
Logical Errors: Functions like timeouts and cancellations might incorrectly report success when no actual game exists.
Potential for Further Exploitation: In combination with other vulnerabilities, this could be used to manipulate contract state in unintended ways.
While this issue might not directly lead to fund theft on its own, it severely undermines the contract's reliability and could be a component in more complex attacks.
Manual code review
Static analysis
Control flow analysis
Add a helper function to validate game existence:
Add validation at the beginning of each function that operates on a game:
For internal functions that are always called after public functions have already validated the game exists, you can add assertions as a defensive programming measure:
Consider implementing a game registry or existence mapping to track valid game IDs.
These measures will ensure that operations are only performed on valid games, improving contract reliability and security.
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.