The root cause is the absence of a grace period expiration check within the claimThrone()
function. While declareWinner()
checks that the gracePeriod
has passed before ending the game, claimThrone()
does not enforce this, allowing a player to frontrun and become the new king even after the grace period has expired. Also, this issue does not explicitly depends on frontrunning since a time can pass between the expiration of the grace period and the call to declareWinner() within which a user can still call claimThrone().
The impact is that declareWinner()
becomes permanently blocked, since each frontrunning claim resets the lastClaimTime
, extending the game indefinitely. Malicious actors can grief legitimate winners or automate DoS for financial or disruptive purposes.
Normally, once the gracePeriod
has elapsed since the last throne claim, anyone can call declareWinner()
to end the game.
However, a malicious user can frontrun this action by calling claimThrone()
just before declareWinner()
is mined, thus resetting the timer and continuing the game without restriction.
The only time check the function does is via gameNotEnded
, but it only checks whether the game has ended or not. A game ends only after declareWinner() is called and since the attacker front runs it they wil be eligible to claim the throne even after grace period expired.
Likelihood:
The likehood is High because:
Happens any time a round is about to end, especially with bots or scripts monitoring the mempool.
Especially likely in high-value pots where incentives are aligned to prevent finalization.
Impact:
The impact is high because the issue:
Makes it impossible for a legitimate winner to claim the pot.
Allows griefing and endless game extension.
The POC demonstrates how a legitimate king is blocked to declare himself and claim his rewards even after grace period expired and the game technically ended.
Add the test bellow to the Game.t.sol
and run the test with the following script:
NOTE: for the poc to work replace the following require statement inside the claimThrone() (which is another issue):
Result:
Add this check in claimThrone()
to ensure no claims can occur after the grace period has passed and before the winner has been declared:
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.