The joinGameWithEth
function in the RockPaperScissors.sol
contract allows any user to become playerB
in a game that is in the Created
state, even if another user has already successfully joined as playerB
. This allows the second joiner to overwrite the first, potentially disrupting the game and loss of fund.
The joinGameWithEth
function performs the necessary checks:
Verifies the game exists (game.playerA != address(0)
).
Ensures the game is accepting players (game.state == GameState.Created
).
Checks if the join deadline has passed (block.timestamp <= game.joinDeadline
).
Confirms the caller is not Player A (msg.sender != game.playerA
).
Validates the correct ETH amount is sent (msg.value == game.bet
).
If these checks pass, it sets game.playerB = msg.sender
. However, crucially, it does not change the game.state
from GameState.Created
.
Because the state remains Created
, another user can call joinGameWithEth
before the joinDeadline
expires and before either player calls commitMove
(which would change the state). This second caller will pass the same checks and will overwrite the game.playerB
address set by the first joiner.
This vulnerability allows a malicious user or simply a concurrent user to replace the intended playerB
. This disrupts the game setup process. The originally joined playerB
might expect to play but finds they have been replaced.
While the ETH sent by the first joiner might eventually be reclaimable via timeoutJoin
if the game never starts properly, the user is denied participation in that specific game instance. It can be used as a griefing vector to prevent specific players from joining games.
Manual code review.
To fix this vulnerability, the joinGameWithEth
function should immediately transition the game state out of Created
once playerB
is successfully set. Changing the state to Committed
seems appropriate, as the next step is for players to commit their moves.
Add the following line within joinGameWithEth
after setting game.playerB
:
Game state remains Created after a player joins
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.