Last Man Standing

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

Platform Fee Manipulation During Active Games Enables 100% Fund Theft

Root + Impact

Description

  • Platform fee update should be allowed only when the game has ended, ensuring that fee distribution remains consistent throughout a game round and players' funds are properly allocated between platform fees and the pot.

  • Current realizatio creates a critical vulnerability where the owner can change the platform fee from 5% to 100% mid-game, causing all subsequent player funds to go directly to platform fees instead of the pot, effectively stealing all player funds.

@> function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external
onlyOwner
@>
isValidPercentage(_newPlatformFeePercentage)
{
platformFeePercentage = _newPlatformFeePercentage;
emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
}

Risk

Likelihood:

  • No complex conditions required, just a single function call

  • Simple parameter update that can be executed immediately

Impact:

  • 100% of player funds can be stolen by redirecting them to platform fees instead of the pot

  • Winners receive nothing as the pot remains empty

Proof of Concept

Test proves updatePlatformFeePercentage during active game vulnerability

function testVulnerability_PlatformFeeManipulation() public {
console2.log("=== PLATFORM FEE VULNERABILITY DEMONSTRATION ===");
// Initial state
console2.log("Initial platform fee percentage:", game.platformFeePercentage(), "%");
assertEq(game.platformFeePercentage(), 5, "Initial platform fee should be 5%");
// Player 1 claims throne with 5% platform fee
uint256 claimAmount = 1 ether;
vm.prank(player1);
game.claimThrone{value: claimAmount}();
uint256 platformFeesBefore = game.platformFeesBalance();
uint256 potBefore = game.pot();
console2.log("\nAfter first claim (5% platform fee):");
console2.log(" Claim amount:", claimAmount);
console2.log(" Platform fees collected:", platformFeesBefore);
console2.log(" Pot amount:", potBefore);
// Expected: 5% platform fee, 95% to pot
uint256 expectedPlatformFee = (claimAmount * 5) / 100; // 0.05 ETH
uint256 expectedPotAmount = claimAmount - expectedPlatformFee; // 0.95 ETH
assertEq(platformFeesBefore, expectedPlatformFee, "Platform fees should be 5%");
assertEq(potBefore, expectedPotAmount, "Pot should be 95%");
// VULNERABILITY: Owner updates platform fee to 100% mid-game
vm.prank(owner);
game.updatePlatformFeePercentage(100);
console2.log("\nAfter platform fee update (100%):");
console2.log(" New platform fee percentage:", game.platformFeePercentage(), "%");
// Player 2 claims throne with 100% platform fee
vm.prank(player2);
game.claimThrone{value: claimAmount}();
uint256 platformFeesAfter = game.platformFeesBalance();
uint256 potAfter = game.pot();
console2.log("\nAfter second claim (100% platform fee):");
console2.log(" Claim amount:", claimAmount);
console2.log(" Platform fees collected:", platformFeesAfter);
console2.log(" Pot amount:", potAfter);
// VULNERABILITY: All funds go to platform fees, nothing to pot!
uint256 platformFeeIncrease = platformFeesAfter - platformFeesBefore;
uint256 potIncrease = potAfter - potBefore;
console2.log("\nVULNERABILITY CONFIRMED:");
console2.log(" Platform fee increase:", platformFeeIncrease);
console2.log(" Pot increase:", potIncrease);
console2.log(" All funds went to platform fees, nothing to pot!");
// CRITICAL VULNERABILITY: 100% of funds go to platform fees
assertEq(platformFeeIncrease, claimAmount, "100% of claim went to platform fees");
assertEq(potIncrease, 0, "0% went to pot (VULNERABILITY!)");
console2.log("\n=== VULNERABILITY IMPACT ===");
console2.log("1. Owner can change platform fee during active game (missing gameEndedOnly modifier)");
console2.log("2. Players' funds go to platform fees instead of pot");
console2.log("3. Winners get nothing (pot is empty)");
console2.log("4. Economic model completely broken");
console2.log("5. Platform fees can be manipulated to steal all funds");
// Calculate the theft amount
uint256 totalTheft = platformFeeIncrease;
console2.log(" Total funds stolen from pot:", totalTheft);
console2.log(" Theft percentage: 100%");
assertGt(totalTheft, 0, "Funds should be stolen from pot");
}

Recommended Mitigation

Simple addition of gameEndedOnly modifier fixes the issue and prevents vulnerability

function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external
onlyOwner
+ gameEndedOnly
isValidPercentage(_newPlatformFeePercentage)
{
platformFeePercentage = _newPlatformFeePercentage;
emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
}
Updates

Appeal created

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

Support

FAQs

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