Last Man Standing

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

Grace Period and Claim Fee Parameters Are Unbounded .

Root + Impact

Description

  • The contract allows the owner to update the values of gracePeriod and initialClaimFee through update functions.

  • However, the setter functions do not enforce any maximum bounds, which can result in extremely high values being set either intentionally or by accident.

This breaks the intended game design where the throne should be regularly contestable with reasonable fees and timeframes.

function updateGracePeriod(uint256 _newGracePeriod) external onlyOwner {
@> require(_newGracePeriod > 0, "Game: New grace period must be greater than zero."); // only check for greater than zero .
gracePeriod = _newGracePeriod;
}
function updateClaimFeeParameters(
uint256 _newInitialClaimFee,
uint256 _newFeeIncreasePercentage
) external onlyOwner isValidPercentage(_newFeeIncreasePercentage) {
@> require(_newInitialClaimFee > 0, "Game: New initial claim fee must be greater than zero."); // only check for greater than zero .
initialClaimFee = _newInitialClaimFee;
}

Risk

Impact High:

  • Players may be priced out from claiming the throne due to prohibitive fees.

  • The game could become unclaimable for extended periods, breaking competition.

  • Such misconfigurations reduce trust and fairness in gameplay.

Likelihood Medium:

  • This will occur when the contract owner (or a compromised owner account) sets gracePeriod to a very high value, e.g., 365 days or more.

  • Similarly, setting initialClaimFee to an excessively high number (e.g., 100 ether) would make it financially inaccessible for most users.

  • This is especially likely during maintenance, updates, or manual parameter adjustments when bounds are not enforced.


Proof of Concept

minimal test demonstrating the flaw:

function test_UpdateGracePeriod_VeryHigh() public {
vm.startPrank(deployer);
game.updateGracePeriod(365 days);
vm.stopPrank();
assertEq(game.gracePeriod(), 365 days, "Grace period should be updated to 365 days");
}
function test_UpdateClaimFeeParameters_VeryHighFee() public {
vm.startPrank(deployer);
game.updateClaimFeeParameters(100 ether, 20); // Set claim fee to 100 ETH and fee increase to 20%
vm.stopPrank();
assertEq(game.initialClaimFee(), 100 ether, "Claim fee should be updated to 100 ETH");
assertEq(game.feeIncreasePercentage(), 20, "Fee increase percentage should be updated to 20");
}
[PASS] test_UpdateGracePeriod_VeryHigh() (gas: 22268)
[PASS] test_UpdateClaimFeeParameters_VeryHighFee() (gas: 30218)

This shows that the game parameters can be configured to absurd levels, harming the playability of the contract.


Recommended Mitigation

To prevent denial-of-service scenarios or configuration misuse caused by unbounded parameter updates, it is recommended to enforce strict upper bounds on both gracePeriod and initialClaimFee. This ensures the contract cannot be rendered unusable due to excessive values and aligns with best practices in smart contract governance.

This following changes implement hard-coded safety limits using constants, and apply require() checks inside the update functions:

// Add these constants at the top of the contract
+ uint256 public constant MAX_GRACE_PERIOD = 7 days;
+ uint256 public constant MAX_INITIAL_CLAIM_FEE = 10 ether;
// Updated function with upper bound enforced
function updateGracePeriod(uint256 _newGracePeriod) external onlyOwner {
+ require(_newGracePeriod <= MAX_GRACE_PERIOD, "Grace period too long");
gracePeriod = _newGracePeriod;
}
// Updated function with upper bound enforced
function updateClaimFeeParameters(
uint256 _newInitialClaimFee,
uint256 _newFeeIncreasePercentage
) external onlyOwner {
+ require(_newInitialClaimFee <= MAX_INITIAL_CLAIM_FEE, "Claim fee too high");
initialClaimFee = _newInitialClaimFee;
feeIncreasePercentage = _newFeeIncreasePercentage;
}

Benefits :

  • Prevents Configuration Abuse: Limits the risk of the owner accidentally or maliciously locking out users.

  • Ensures Protocol Availability: Guarantees that users will always be able to participate in the throne claiming process.

  • Improves Security Posture: Avoids introducing infinite loop potential or extreme economic disincentives (e.g., claim fees of 1000 ETH).

  • Best Practice: Parameter bounding is a common industry practice for upgradable and governed contracts.

If additional flexibility is desired, these limits can be made adjustable by governance, but should never be fully unbounded.


Updates

Appeal created

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