The intended behavior is that a player can take the stage as a defender by staking a CRED
token bet and locking their NFT. Another player can then challenge with a matching bet and their NFT, after which the contract determines a winner and pays out the pooled bets.
The problem is that once a defender goes on stage, there is no mechanism for the defender (or anyone else) to cancel or withdraw if no challenger arrives. This allows a defender to lock the arena indefinitely or set a bet size that no one can match, blocking the arena for all other players. In the process, the defender’s bet and NFT are also locked forever.
Likelihood:
A defender always sets arena.defender
and arena.defender_bet
when going on stage, with no timeout or cancel function.
Attackers can trivially call this once with a very high bet or simply never intend to battle, leaving the arena locked.
Impact:
Denial of Service: No other users can use the arena once locked.
Permanent loss of funds/NFT: Defender’s stake and NFT remain trapped unless a challenger with the exact bet appears — which may never happen.
Add a cancellation or timeout mechanism that allows a defender to reclaim their NFT and bet if no challenger arrives:
Alternatively, enforce a time-based expiration (e.g., using timestamp::now_seconds()
) so that if no challenger joins within X
seconds, the defender can safely withdraw.
There is no security impact on the protocol from this issue. The defender should wait until the challenger joins, this is intended behavior.
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.