Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: low
Invalid

Game Round Counter Can Theoretically Overflow

Root + Impact

Description

  • Normal behavior:
    Round counters should use appropriately sized types and include overflow protection for data integrity.

    Specific issue:
    The contract uses uint256 for gameRound which increments indefinitely without bounds checking or overflow protection.

uint256 public gameRound; // @> Oversized type, no overflow protection
function resetGame() external onlyOwner gameEndedOnly {
// ...
gameRound = gameRound + 1; // @> No overflow protection
// ...
}

Risk

Likelihood:

  • Overflow is extremely unlikely but theoretically possible with automated systems running indefinitely.

Impact:

  • Round tracking would reset to 0, causing confusion and breaking analytics.

  • Historical round data becomes incorrect.

  • Gas inefficiency from using oversized storage type.

Proof of Concept

The following test demonstrates the unbounded round counter increment:

function testGameRoundCanOverflow() public {
// Show that gameRound uses uint256 and increments without bounds
uint256 initialRound = game.gameRound();
assertEq(initialRound, 1, "Should start at round 1");
// Simulate multiple rounds
for (uint256 i = 0; i < 5; i++) {
// Player claims throne
vm.startPrank(player);
game.claimThrone{value: 0.1 ether}();
vm.stopPrank();
// End round
vm.warp(block.timestamp + 1 days + 1);
game.declareWinner();
// Reset game (increments gameRound)
vm.startPrank(deployer);
game.resetGame();
vm.stopPrank();
}
// gameRound incremented to 6
assertEq(game.gameRound(), 6, "Round should increment");
// While overflow is extremely unlikely with uint256,
// using a smaller type like uint32 would be more appropriate
uint256 maxUint256 = type(uint256).max;
console2.log("uint256 max value:", maxUint256);
console2.log("Current round:", game.gameRound());
}

Recommended Mitigation

Use a smaller, more appropriate data type and add overflow protection:

- uint256 public gameRound;
+ uint32 public gameRound; // Sufficient for 4+ billion rounds
function resetGame() external onlyOwner gameEndedOnly {
// ...
+ require(gameRound < type(uint32).max, "Game: Maximum rounds reached");
gameRound = gameRound + 1;
// ...
}
Updates

Appeal created

inallhonesty Lead Judge 13 days ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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