An attacker controlling two addresses (playerA
and playerB
) can exploit a mismatch between token-based and ETH-based game mechanics to illegitimately gain one extra WinningToken
per game.
The attack proceeds as follows:
playerA
creates a game using createGameWithToken()
with a bet amount of 0, and transfers 1 token to the contract.
playerB
(also controlled by the attacker) joins the game using joinGameWithEth()
and sends no ETH
, since game.bet == 0
.
Both players commit their moves.
Only playerA
reveals their move.
After the reveal timeout, playerA
calls timeoutReveal()
, which declares them the winner and transfers 2 tokens to playerA
.
Because playerB
never actually staked any ETH
or tokens, the second token received by playerA
is unbacked and illegitimately obtained. This loop can be repeated indefinitely.
If the vulnerability is not detected in time, an attacker can exploit it continuously and silently, generating new WinningToken
out of thin air without any real cost or risk. This illegitimate token creation can lead to constant economic losses for the contract and for legitimate users, especially if the tokens hold any monetary value or are used to access rewards.
AttackerA receives 1 token
AttackerA creates a token-based game
AttackerB joins using ETH-based function (no value sent)
Both commit, but only AttackerA reveals
Timeout is triggered → AttackerA wins and receives 2 tokens
Manual Review and Foundry
Game state remains Created after a player joins
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.