circuits/src/main.nr ->Recipient public input is never used in any circuit constraintThe claim() function accepts a recipient address as a public input and passes it to the verifier. The Noir circuit is designed to bind the proof to a specific recipient to prevent replay attacks.
The recipient field is declared as a public input in the circuit but is never used in any constraint. A proof generated for one recipient is valid for any other recipient, making the binding completely ineffective.
Likelihood:
Likelihood:
A legitimate participant submits a claim() transaction, it is visible in the public mempool before inclusion, giving attackers the proof bytes and treasure hash
MEV bots and searchers routinely monitor the mempool for profitable front-running opportunities with no manual effort required
Impact:
An attacker copies the proof from the mempool and resubmits it with their own address as recipient , stealing the 10 ETH reward from the legitimate finder
Every single treasure claim is vulnerable , no participant can safely claim any reward on a live network
Include recipient in the pedersen hash preimage so the proof // is cryptographically bound to a specific recipient address. Bind recipient into the proof by hashing it with the treasure.
NOTE: ALLOWED_TREASURE_HASHES and the off-chain hash generation must also be updated to use pedersen_hash([treasure, recipient])
The claim that the proof system is broken because the recipient is not explicitly constrained in the Noir circuit reflects a misunderstanding of how zero-knowledge proofs bind public inputs. Although the circuit does not impose algebraic constraints on recipient, the value is still included in the public input vector, which is cryptographically committed to during proof generation. As a result, the proof is only valid for the exact tuple of public inputs it was created with. Any attempt by an attacker to front-run and substitute a different recipient would alter this tuple, causing the verifier’s check to fail because the proof no longer matches the provided public inputs. Therefore, while unconstrained public inputs do not enforce logical relationships within the circuit, they remain inseparably bound to the proof itself, and this binding is sufficient to prevent tampering or replay with modified values. Run the unit tests 'testClaimInvalidProofFails', 'testFrontRunningClaimFails'.
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.