Last Man Standing

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

Off-by-One Timing in Winner Declaration Can Be Exploited with Block Timestamp

Off-by-One Timing in Winner Declaration Can Be Exploited with Block Timestamp

Description

  • In a time-based logic like declareWinner, correctness depends on precise comparison against the grace period deadline.

  • This introduces a 1-second window of ambiguity at the exact moment of expiry. If block.timestamp == lastClaimTime + gracePeriod, the winner cannot be declared, even though the grace period should be considered expired.

  • Worse, an attacker could manipulate or mine a block at that exact timestamp, stalling winner declaration for a block.

  • The current implementation uses:

require(block.timestamp > @>lastClaimTime + gracePeriod<@, "Game: Grace period has not expired yet.");

Risk

Likelihood:

  • Very likely in active networks with small gracePeriod values (e.g., < 1 min).

  • Block producers (especially in testnets or low-difficulty chains) can influence block.timestamp.


Impact:

  • Prevents timely winner declaration.

  • Can be exploited to delay game resolution, especially if combined with front-running or selfish mining.

Proof of Concept

// Suppose:
lastClaimTime = 1000;
gracePeriod = 60;
// Block mined at timestamp 1060:
block.timestamp = 1060;
// Condition fails:
require(1060 > 1060) // false — revert!
// Even though 60 seconds have passed.

Recommended Mitigation

- require(block.timestamp > lastClaimTime + gracePeriod, "Game: Grace period has not expired yet.");
+ require(block.timestamp >= lastClaimTime + gracePeriod, "Game: Grace period has not expired yet.");
Updates

Appeal created

inallhonesty Lead Judge about 2 months ago
Submission Judgement Published
Invalidated
Reason: Design choice

Support

FAQs

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