The timeoutJoin
function in the RockPaperScissors contract can be called with any arbitrary game ID, including non-existent ones. This leads to phantom event emissions that can disrupt off-chain services and potentially cause confusion in the game state tracking.
The timeoutJoin
function does not validate if the provided game ID actually exists before processing the timeout:
When accessing a non-existent game through the games
mapping:
The returned Game
struct contains default values (0 for uint, address(0) for address)
These default values pass all the require checks:
game.state == GameState.Created
(true because GameState.Created = 0)
block.timestamp > game.joinDeadline
(true because joinDeadline = 0)
game.playerB == address(0)
(true because playerB = address(0))
As demonstrated by the test:
Event Spam:
The function emits GameCancelled
events for non-existent games
This can pollute event logs and confuse off-chain services
Indexers and UIs relying on these events may show incorrect game states
Resource Waste:
Each phantom cancellation consumes gas
Creates unnecessary blockchain bloat
Increases costs for indexing services
User Experience:
Players might see cancelled games that never existed
Could lead to confusion about game state and history
Potential for griefing by spamming phantom game cancellations
Output from test:
Manual code review
Foundry testing framework
Add explicit game existence validation:
Implement a game registry to track valid games:
While not directly leading to fund loss, this vulnerability can disrupt system operation and create confusion in game state tracking, off-chain services
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.