Last Man Standing

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

Unprotected ETH Reception Leading to Permanent Fund Lock

Root + Impact

Description

  • Normally, ETH should only enter the contract through the claimThrone() function where it's properly distributed to the pot, previous king, and platform fees.

  • The current implementation allows direct ETH transfers via an unprotected receive() function, causing funds to become permanently stuck with no allocation mechanism.

@> receive() external payable {}
// No logic to handle received ETH - funds remain stranded in contract

Risk

Likelihood: High

  • Occurs in three common scenarios:

    1. Users accidentally sending ETH via wallet interfaces

    2. Other contracts forwarding ETH without using claimThrone()

    3. Misconfigured multisig transactions

  • Any contract interaction using .transfer() or .send() will trigger this vulnerability

Impact: Critical

  • Fund Loss: ETH becomes irrecoverable.

  • Accounting Corruption: Creates imbalance between:

    address(this).balance != pot + platformFeesBalance + pendingWinnings
  • Contract Immutability: Requires redeployment to fix if funds get stuck

Proof of Concept

// Attack Simulation
function testStuckETH() public {
// User accidentally sends 1 ETH directly (not via claimThrone)
(bool sent,) = address(game).call{value: 1 ether}("");
require(sent, "Transfer failed");
// Contract balance increases but pot/platformFees don't
assertEq(address(game).balance, 1 ether);
assertEq(game.pot(), 0); // Pot unchanged
assertEq(game.platformFeesBalance(), 0); // Fees unchanged
// No way to withdraw the 1 ETH
}

Recommended Mitigation


Option 1: Reject All Direct Transfers (Recommended)

receive() external payable {
revert("Use claimThrone() to participate");
}

Pros:

  • Prevents all accidental transfers

  • Clear error messaging

  • Gas-efficient revert

Option 2: Redirect to Pot (If Accepting Donations)

receive() external payable {
pot += msg.value;
emit DonationReceived(msg.sender, msg.value);
}

Pros:

  • Recovers value from mistakes

  • Maintains accounting integrity

Cons:

  • Slightly higher gas cost

Updates

Appeal created

inallhonesty Lead Judge about 1 month ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Direct ETH transfers - User mistake

There is no reason for a user to directly send ETH or anything to this contract. Basic user mistake, info, invalid according to CH Docs.

Support

FAQs

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