Last Man Standing

First Flight #45
Beginner FriendlyFoundrySolidity
100 EXP
View results
Submission Details
Severity: medium
Valid

Current King Can Block All Future Claims

Current King Prevents All Other Players From Claiming the Throne

Description

  • The game is designed so that any player can claim the throne by sending the required ETH fee, with the throne passing to the new player after payment

  • There's a critical logic error in the claimThrone() function that prevents anyone except the current king from claiming the throne, effectively breaking the core game mechanics

function claimThrone() external payable gameNotEnded nonReentrant {
require(msg.value >= claimFee, "Game: Insufficient ETH sent to claim the throne.");
require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim."); // @> This check prevents anyone else from becoming king
// Rest of the function logic...
}

Risk

Likelihood: High

  • This vulnerability is triggered whenever any player (other than the current king) attempts to claim the throne

  • The incorrect logic check happens on every throne claiming attempt

  • Once someone becomes the first king, the game becomes permanently locked

Impact: High

  • Complete breakdown of the core game functionality - no throne changes can occur

  • First king becomes permanent winner as no one else can ever claim the throne

  • All ETH sent by other players attempting to claim the throne will be reverted

  • Game becomes unplayable after the first successful claim

Proof of Concept

// After deployment, player1 becomes the first king
vm.prank(player1);
game.claimThrone{value: INITIAL_CLAIM_FEE}(); // This succeeds
// Now player2 tries to claim with sufficient funds
vm.prank(player2);
vm.expectRevert("Game: You are already the king. No need to re-claim.");
game.claimThrone{value: nextClaimFee}(); // This will always fail
// The game is now permanently broken - only player1 can call claimThrone

Explanation: The require statement incorrectly uses == instead of !=, allowing only the current king to call the function. This breaks the core game mechanic where other players should overthrow the king.

Recommended Mitigation

function claimThrone() external payable gameNotEnded nonReentrant {
require(msg.value >= claimFee, "Game: Insufficient ETH sent to claim the throne.");
- require(msg.sender == currentKing, "Game: You are already the king. No need to re-claim.");
+ require(msg.sender != currentKing, "Game: You are already the king. No need to re-claim.");
// Rest of function logic remains the same...
}

Explanation: Change == to != so only non-kings can claim the throne, restoring the competitive gameplay where players can overthrow the current king.

Updates

Appeal created

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Game::claimThrone `msg.sender == currentKing` check is busted

Support

FAQs

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

Give us feedback!