Last Man Standing

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

Critical Logic Error in claimThrone Function Due to Reversed Access Check

Root + Impact

Description


The claimThrone function is intended to allow any player to claim the throne by paying the required fee, thereby dethroning the current king. This is the core mechanic of the game.

However, a critical logic error in the access control condition prevents any new player from claiming the throne. Instead, it incorrectly allows only the current king to call the function, which defeats the purpose of the game.

The condition msg.sender == currentKing reverts the transaction for anyone who is not the current king, meaning only the existing king can pass this check. But since the king already holds the throne, they have no reason to re-claim it. The subsequent state update currentKing = msg.sender is therefore unreachable for any challenger.

// Root cause in the codebase with @> marks to highlight the relevant section
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.");
...
@> currentKing = msg.sender;

Risk

Likelihood:

  • Every time a user attempts to claim the throne as a challenger, the transaction will revert due to the incorrect equality check.

  • The function can only succeed if the current king calls it again, leading to redundant claims with no change in state.

Impact:

  • The throne becomes permanently unchallengeable after the first claim, freezing the game state.

  • The core gameplay loop is broken, rendering the contract non-functional for its intended purpose.

Proof of Concept

No additional PoC is required. The issue is evident from reading the code:
Alice claims the throne (becomes currentKing).
Bob sends claimFee or more to claimThrone().
The check msg.sender == currentKing evaluates to false (Bob ≠ Alice).
Transaction reverts with "You are already the king."
Bob cannot claim, and no one else ever can.

Recommended Mitigation

- remove this code
+ add this code
-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.");
Updates

Appeal created

inallhonesty Lead Judge about 1 month 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.