The Noir circuit defines recipient as a public input intended to bind a zero-knowledge proof to a specific payout address. However, the recipient variable is never used in any circuit constraint, meaning it is not enforced during proof verification.
In zk-SNARK circuits, public inputs are only meaningful if they participate in constraints. Since recipient is not used anywhere in the circuit logic, it is effectively unconstrained and can be set to any value without affecting proof validity.
The circuit only enforces:
The treasure_hash is in the allowed set
The treasure_hash equals Pedersen(treasure)
There is no cryptographic link between the recipient and the proof.
As a result, a valid proof can be reused with a different recipient, breaking the intended replay-resistance mechanism and enabling reward redirection.
This issue breaks the protocol’s core assumption that proofs are bound to a specific recipient.
An attacker can intercept a valid proof submission from the mempool, replace the recipient address with their own, and still pass verification successfully.
Reward redirection to attacker-controlled addresses
Broken replay-resistance guarantees
Loss of integrity in proof-to-recipient binding
Enables straightforward front-running attacks
This results in fund theft with minimal effort, making the issue Critical severity.
A valid proof is generated off-chain for a treasure:
The honest user submits:
The attacker copies the same proof and treasureHash from the mempool.
The attacker modifies only the recipient:
Inside the circuit:
However, recipient is never used in any constraint, meaning it is not enforced by the proof system.
Therefore:
The same proof is valid for any recipient
Changing the recipient does not invalidate the proof
A user finds a valid treasure and generates a proof:
treasure = secret
treasure_hash = H(secret)
recipient = Alice
They submit:
An attacker monitors the mempool and copies:
proof
treasureHash
The attacker resubmits the same proof but changes the recipient:
The proof still verifies successfully
Because recipient is not enforced in the circuit
The contract accepts the modified recipient
Reward is transferred to the attacker instead of the original prover
Inside the circuit:
However, recipient is never used in any constraint, making it completely unbound and non-verifiable.
The recipient must be explicitly included in circuit constraints so it becomes part of the cryptographic proof.
Bind recipient into the Pedersen hash:
This ensures the proof is uniquely tied to both the treasure and the recipient.
Requires regeneration of all allowed treasure hashes and circuit artifacts.
Separate treasure identity and recipient binding:
Where:
treasure_hash verifies the secret
binding enforces recipient-specific validity
This design prevents replay attacks while keeping responsibilities separated.
After applying the fix:
Proofs are cryptographically bound to recipients
Proof replay with modified recipients becomes invalid
Front-running and reward redirection are prevented
The protocol’s intended security guarantees are restored
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.