joinGameWithEth
function doesn't explicitly change the game state from GameState.Created to another state after Player B joins. It only sets game.playerB = msg.sender. Player C could call joinGameWithEth with the same _gameId and replace Player B, as long as they send the correct bet amount.
The joinGameWithEth function doesn't properly protect against overwriting of Player B's address:
The function doesn't check if Player B already exists, nor does it change the game state after Player B joins.
A malicious actor (Player C) can monitor the blockchain for recently joined games and replace legitimate Player B by calling joinGameWithEth with the same game ID. This allows:
Front-running attacks to steal desirable games from legitimate players
Original Player B loses their position in the game
Original Player B's ETH is stuck in the contract with no easy way to recover it
Manual code review
Add a check to ensure Player B hasn't already joined or update the game state in the join functions:
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.