Rock Paper Scissors

First Flight #38
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: medium
Invalid

Lack of Access Control in `createGameWithEth` function

Summary

The createGameWithEth function is marked as external, and it lacks access control allowing any user to call it.

Vulnerability Details

Vulnerable Contract: RockPaperScissors.sol

Vulnerable Function: createGameWithEth

The function is marked external and has no modifiers or role checks. Without proper access control in place, malicious actors can manipulate and flood the contract with game creation, which can also lead to a Denial of Service (DoS) attacks.

function createGameWithEth(uint256 _totalTurns, uint256 _timeoutInterval) external payable returns (uint256) {
require(msg.value >= minBet, "Bet amount too small");
require(_totalTurns > 0, "Must have at least one turn");
require(_totalTurns % 2 == 1, "Total turns must be odd");
require(_timeoutInterval >= 5 minutes, "Timeout must be at least 5 minutes");
uint256 gameId = gameCounter++;
Game storage game = games[gameId];
game.playerA = msg.sender;
game.bet = msg.value;
game.timeoutInterval = _timeoutInterval;
game.creationTime = block.timestamp;
game.joinDeadline = block.timestamp + joinTimeout;
game.totalTurns = _totalTurns;
game.currentTurn = 1;
game.state = GameState.Created;
emit GameCreated(gameId, msg.sender, msg.value, _totalTurns);
return gameId;
}

Proof of Concept (POC)

Below is a test in foundry to show how it might work.

add the following to RockPaperScissorsTest.t.sol file

function testAccessControlVulnerability() public {
// Test unlimited game creation
vm.deal(playerA, 10 ether);
vm.startPrank(playerA);

function testAccessControlVulnerability() public {
// Test unlimited game creation
vm.deal(playerA, 10 ether);
vm.startPrank(playerA);
uint256 firstGame = game.createGameWithEth{value: 1 ether}(3, 10 minutes);
uint256 secondGame = game.createGameWithEth{value: 1 ether}(5, 10 minutes);
uint256 thirdGame = game.createGameWithEth{value: 1 ether}(7, 10 minutes);
vm.stopPrank();
assertTrue(firstGame != secondGame && secondGame != thirdGame);
}
function testGameSpamAttack() public {
vm.deal(playerA, 100 ether);
vm.startPrank(playerA);
for (uint i = 0; i < 10; i++) {
game.createGameWithEth{value: 1 ether}(3, 10 minutes);
}
vm.stopPrank();
assertEq(game.gameCounter(), 10);
}

When you run forge test --match-test testAccessControlVulnerability , the test should pass.

Impact

  • An attacker can monitor the mempool and thus frontrun other players.

  • An attacker can create multiple games to distort the entire system.

Tools Used

  • Manual Review

  • Foundry

Recommendations

Make use of OpenZeppelin’s AccessControl to implement role-based permissions for the createGameWithEth function to protect against spam and abuse of contract.

Updates

Appeal created

m3dython Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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