Root Cause:
updateGracePeriod
writes directly to the livegracePeriod
used bydeclareWinner()
instead of the initial templateinitialGracePeriod
, with no upper bound → Impact: Owner can set an effectively infinite deadline, blocking game conclusion forever.
WHY WOULD ANYONE TRUST THE OWNER: It's a Game something similar to a gamble. So we can't expect the owner to be fair. The owner can change the rules at any time, so we can't expect the game to be fair.
The updateGracePeriod(uint256 _newGracePeriod)
function in Game.sol
is intended to adjust the default timing for future rounds,
but it immediately overwrites the active gracePeriod
variable used by the current round’s declareWinner()
logic. With no maximum limit, the owner can set gracePeriod
so large that:
Likelihood: High
Never becomes true, permanently preventing declareWinner()
from succeeding. This action effectively freezes the game, locking users out and trapping the pot indefinitely.
Active Lock: Because gracePeriod
governs the current round, updating it mid-round alters the deadline in real time.
Unbounded: Without a cap, _newGracePeriod
can be set near 2^256-1
, ensuring the grace check in declareWinner()
always fails.
Impact: High
Permanent Lock: No winner can ever be declared; the game is stuck in limbo.
Trapped Funds: The accumulated pot remains inaccessible.
User Frustration: Players lose confidence when the game never resolves.
Single-Point Abuse: A malicious or compromised owner can sabotage the entire contract.
Similar fate befell early “last man standing” games on Ethereum, where misordered admin functions or unbounded parameters allowed operators to halt play and seize or lock up funds.
Tools Used:
Foundry Test Suite
Chat-GPT AI Assistance (Report Grammar Check & Improvements)
Manual Review
step 1: go to test/Game.t.sol
file
step 2: paste the above code ⬆️
step 3: run the test suite
step 4: See the Output
Scenario:
Multiple Claims
Player1, Player2, Player3 sequentially call claimThrone()
, updating lastClaimTime
each time.
Owner Freeze
The owner then calls:
Blocked Conclusion
When any player calls:
it reverts with
Since lastClaimTime + gracePeriod
exceeds any realistic timestamp, the game is frozen indefinitely.
Update initialGracePeriod
, Not Active
– This ensures only future rounds use the new interval.
Enforce an Upper Bound
```solidity
uint256 constant MAX_GRACE_PERIOD = 7 days;
require(_newGracePeriod <= MAX_GRACE_PERIOD, "Game: Grace period too long.");
```
Prevent Mid-Round Changes
```solidity
require(gameEnded, "Game: Cannot update during an active round.");
```
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.