Last Man Standing

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

100% Platform Fee Attack

Root + Impact

Description

  • The updatePlatformFeePercentage() function should allow the owner to adjust platform fees within reasonable bounds to maintain sustainable game economics while ensuring the pot continues to grow from player contributions. Platform fees should represent a modest percentage (typically 5-20%) that allows the contract owner to earn revenue without destroying the core game incentive structure where players compete for an accumulating prize pot.

  • The updatePlatformFeePercentage() function only validates that the new percentage is between 0-100% but lacks reasonable upper bounds, allowing the owner to set platformFeePercentage = 100%. When set to 100%, all future claim fees are diverted to the owner's platform balance instead of contributing to the pot, effectively converting the game from a competitive prize mechanism into a direct profit extraction tool. This breaks the fundamental game economics by ensuring the pot never grows, eliminating player incentives to participate and transforming the contract into a disguised donation mechanism for the owner.

function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external
onlyOwner
isValidPercentage(_newPlatformFeePercentage)
{
@> platformFeePercentage = _newPlatformFeePercentage; // NO REASONABLE UPPER BOUND
emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
}
modifier isValidPercentage(uint256 _percentage) {
@> require(_percentage <= 100, "Game: Percentage must be 0-100."); // ALLOWS 100%
_;
}

Risk

Likelihood:

  • This attack becomes viable whenever the owner decides to maximize short-term profits over long-term game sustainability, as the function can be called at any time without player consent or advance notice to immediately redirect all future revenues

  • The vulnerability activates through gradual fee increases that avoid immediate detection, allowing the owner to incrementally raise fees from reasonable levels to 100% over time while players remain engaged in the game mechanics

Impact:

  • Complete elimination of pot growth and prize accumulation, as 100% of all claim fees are diverted to the owner's platform balance instead of contributing to the competitive prize pool that motivates player participation

  • Destruction of the core game economics and player incentive structure, effectively converting the competitive game into a disguised donation mechanism where players unknowingly fund the owner's profits while receiving no meaningful prize potential

Proof of Concept

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test, console2} from "forge-std/Test.sol";
import {Game} from "../src/Game.sol";
/**
* @title MEDIUM-002 PoC: 100% Platform Fee Attack
* @notice Demonstrates how owner can set platform fees to 100% and drain all future claims
*/
contract PlatformFeeAttackPoC is Test {
Game public game;
address public maliciousOwner;
address public player1;
address public player2;
uint256 public constant INITIAL_CLAIM_FEE = 0.1 ether;
uint256 public constant GRACE_PERIOD = 1 days;
uint256 public constant FEE_INCREASE_PERCENTAGE = 10;
uint256 public constant INITIAL_PLATFORM_FEE = 5; // 5%
function setUp() public {
maliciousOwner = makeAddr("maliciousOwner");
player1 = makeAddr("player1");
player2 = makeAddr("player2");
vm.deal(maliciousOwner, 10 ether);
vm.deal(player1, 10 ether);
vm.deal(player2, 10 ether);
// Deploy with reasonable initial fees
vm.prank(maliciousOwner);
game = new Game(
INITIAL_CLAIM_FEE,
GRACE_PERIOD,
FEE_INCREASE_PERCENTAGE,
INITIAL_PLATFORM_FEE
);
}
/**
* @notice Demonstrates 100% platform fee attack
*/
function test_HundredPercentPlatformFeeAttack() public {
// Initial state - reasonable fees
assertEq(game.platformFeePercentage(), INITIAL_PLATFORM_FEE);
// Malicious owner sets platform fee to 100%
vm.prank(maliciousOwner);
game.updatePlatformFeePercentage(100);
assertEq(game.platformFeePercentage(), 100);
console2.log("Platform fee set to 100% by malicious owner");
// Note: Due to CRITICAL-001, players cannot actually claim
// But we can demonstrate the impact if they could
uint256 claimAmount = 1 ether;
uint256 expectedPlatformFee = (claimAmount * 100) / 100; // 100%
uint256 expectedToPot = claimAmount - expectedPlatformFee; // 0
console2.log("If a player sent", claimAmount, "wei:");
console2.log("Platform fees would get:", expectedPlatformFee, "wei (100%)");
console2.log("Pot would get:", expectedToPot, "wei (0%)");
assertEq(expectedToPot, 0);
assertEq(expectedPlatformFee, claimAmount);
}
/**
* @notice Shows how owner can gradually increase fees to avoid detection
*/
function test_GradualFeeIncrease() public {
console2.log("Gradual fee increase attack:");
// Start with reasonable fees
console2.log("Initial platform fee:", game.platformFeePercentage(), "%");
// Gradually increase to avoid suspicion
vm.startPrank(maliciousOwner);
game.updatePlatformFeePercentage(25);
console2.log("Increased to:", game.platformFeePercentage(), "%");
game.updatePlatformFeePercentage(50);
console2.log("Increased to:", game.platformFeePercentage(), "%");
game.updatePlatformFeePercentage(75);
console2.log("Increased to:", game.platformFeePercentage(), "%");
game.updatePlatformFeePercentage(100);
console2.log("Final platform fee:", game.platformFeePercentage(), "%");
vm.stopPrank();
assertEq(game.platformFeePercentage(), 100);
console2.log("Owner can now capture 100% of all future claims");
}
/**
* @notice Demonstrates impact on game economics
*/
function test_GameEconomicsDestruction() public {
// Set 100% platform fee
vm.prank(maliciousOwner);
game.updatePlatformFeePercentage(100);
console2.log("=== GAME ECONOMICS IMPACT ===");
console2.log("With 100% platform fee:");
console2.log("- All claim fees go to owner");
console2.log("- Pot never grows");
console2.log("- No incentive for players to participate");
console2.log("- Game becomes owner profit extraction mechanism");
// Demonstrate calculation
uint256 hypotheticalClaim = 2 ether;
uint256 platformFee = (hypotheticalClaim * game.platformFeePercentage()) / 100;
uint256 toPot = hypotheticalClaim - platformFee;
assertEq(toPot, 0);
assertEq(platformFee, hypotheticalClaim);
console2.log("Hypothetical", hypotheticalClaim, "wei claim:");
console2.log("To pot:", toPot, "wei");
console2.log("To owner:", platformFee, "wei");
}
/**
* @notice Shows lack of reasonable bounds checking
*/
function test_NoReasonableBounds() public {
console2.log("=== BOUNDS CHECKING ANALYSIS ===");
// Current validation only checks <= 100%
console2.log("Current validation: percentage <= 100");
console2.log("Missing: reasonable upper bound (e.g., 20%)");
// Owner can set any value up to 100%
vm.startPrank(maliciousOwner);
// These all pass validation
game.updatePlatformFeePercentage(99);
assertEq(game.platformFeePercentage(), 99);
game.updatePlatformFeePercentage(95);
assertEq(game.platformFeePercentage(), 95);
game.updatePlatformFeePercentage(100);
assertEq(game.platformFeePercentage(), 100);
vm.stopPrank();
console2.log("All extreme values pass validation");
console2.log("Recommendation: Add reasonable upper bound (e.g., 20%)");
}
/**
* @notice Shows this breaks the core game mechanic
*/
function test_CoreGameMechanicBreakage() public {
vm.prank(maliciousOwner);
game.updatePlatformFeePercentage(100);
console2.log("=== CORE GAME IMPACT ===");
console2.log("Game premise: Players compete for growing pot");
console2.log("With 100% fees: Pot never grows, no competition incentive");
console2.log("Result: Game becomes meaningless");
// The pot calculation would always be 0
uint256 anyClaimAmount = 5 ether;
uint256 platformTake = (anyClaimAmount * 100) / 100;
uint256 potGrowth = anyClaimAmount - platformTake;
assertEq(potGrowth, 0);
console2.log("Any claim amount results in 0 pot growth");
console2.log("Game mechanic completely broken");
}
}

This PoC proves the vulnerability by demonstrating that the owner can legally set platform fees to 100%, effectively redirecting all player claim fees to their own balance. The tests show multiple attack scenarios including direct 100% fee setting,


Recommended Mitigation

Add a reasonable upper bound (e.g., 20%) to prevent the owner from setting excessive platform fees that would destroy game economics

function updatePlatformFeePercentage(uint256 _newPlatformFeePercentage)
external
onlyOwner
isValidPercentage(_newPlatformFeePercentage)
{
+ require(_newPlatformFeePercentage <= 20, "Game: Platform fee cannot exceed 20%.");
platformFeePercentage = _newPlatformFeePercentage;
emit PlatformFeePercentageUpdated(_newPlatformFeePercentage);
}
Updates

Appeal created

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!