claim() validates the recipient address against several invalid cases. The ZK circuit binds the recipient into the proof as a public input, which already prevents a front-runner from redirecting a stolen proof to themselves. The verifier would reject any proof where the submitted recipient differs from the one committed in the circuit.
Despite this cryptographic protection, claim() additionally rejects any call where recipient == msg.sender, forcing every participant to use a second address to receive their own reward.
Likelihood:
Affects every participant who tries to claim their own reward at the submitting address a natural and common pattern.
Impact:
Participants who control only one address cannot claim their reward without setting up a second wallet.
Creates unnecessary friction that may result in legitimate finders being unable to claim before the hunt ends.
A participant who controls only one wallet address and generates a proof with their own address as the recipient cannot claim their reward. The circuit binds the recipient into the proof, so they cannot simply change the recipient to a second address after the fact a new proof would need to be generated. This forces every single-wallet participant into a multi-step workaround to collect a reward they legitimately earned.
The recipient == msg.sender condition provides no security value because the ZK circuit already cryptographically binds the recipient at proof-generation time — a third party cannot redirect the reward even without this check. Removing the condition restores the natural and expected behavior (paying the submitter directly) without weakening any security property. The other three conditions (address(0), address(this), owner) guard against genuinely dangerous recipient values and should be retained.
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.
The contest is complete and the rewards are being distributed.