Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Logic Flaw Allows Free Entry into Token-Based Games via ETH Join Function

Summary

A logical vulnerability exists in the RockPaperScissors smart contract, specifically in the joinGameWithEth function. The contract fails to validate whether the game being joined is an ETH-based game or a token-based game, leading to a critical inconsistency. This allows malicious players to join token-based games using 0 ETH, bypassing the required entry conditions.


Vulnerability Details

The vulnerability lies in the lack of a check within the joinGameWithEth function to confirm that the game being joined was originally created as an ETH-bet game. This function assumes all games it handles require ETH, but the contract supports a parallel system where games can be created using WinningToken instead of ETH.

function joinGameWithEth(uint256 _gameId) external payable {
Game storage game = games[_gameId];
require(game.state == GameState.Created, "Game not open to join");
require(game.playerA != msg.sender, "Cannot join your own game");
require(block.timestamp <= game.joinDeadline, "Join deadline passed");
require(msg.value == game.bet, "Bet amount must match creator's bet");
game.playerB = msg.sender;
emit PlayerJoined(_gameId, msg.sender);
}

There is no validation ensuring game.bet > 0, which means a malicious actor can:

  1. Locate or monitor for games created via createGameWithToken, where game.bet == 0.

  2. Call joinGameWithEth(_gameId) and send msg.value == 0.

  3. Successfully join a token-based game without holding or transferring the required WinningToken.

This undermines the economic model and fairness of the contract.


Impact

This vulnerability enables:

  • Unauthorized participation in token-based games without fulfilling the token requirement.

  • Economic exploitation, where users bypass the token staking mechanism entirely, disrupting the designed incentive model.

  • Game state corruption, potentially causing inconsistencies in logic flow and unexpected behavior in later game phases (e.g., prize distribution or score tracking).

  • Loss of trust, as honest players who participate according to the rules may end up competing against players who didn’t meet the same entry criteria.

This is a critical severity issue due to the potential for misuse and the violation of the core rules of game entry.


Tools Used

  • Manual source code review

  • Static analysis (via IDE/VSCode/Hardhat plugin)

  • Logical reasoning (no formal tools needed in this specific case)


Recommendations

Add a condition in joinGameWithEth to ensure the target game was created with ETH as the betting mechanism. Specifically:

require(game.bet > 0, "This game requires token to join");

This should be inserted before any assignment or state change. Additionally, you may consider:

  • Introducing a boolean flag (e.g., isEthGame) to the Game struct to make type-checking more explicit and efficient.

  • Applying the same principle to joinGameWithToken to ensure symmetry and robustness.

  • Adding tests to cover edge cases where ETH-based and token-based logic might be misused or intersect unexpectedly.

Updates

Appeal created

m3dython Lead Judge about 2 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Game Staking Inconsistency

joinGameWithEth function lacks a check to verify the game was created with ETH

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.