Scope: contracts/scripts/Deploy.s.sol, circuits/src/main.nr
The Noir circuit proves knowledge of a preimage treasure for one of
10 allowed Pedersen hashes. This hides which treasure the prover
found, but only if the secret space itself is hard to brute-force and
is not publicly disclosed.
Two independent problems break that security assumption:
(a) The secrets are tiny-integer plaintext and are published in the
in-scope Deploy.s.sol.
The deploy script is in scope per the contest README, and the comments
literally enumerate all 10 secret values and their Pedersen hashes.
Anyone who reads the public GitHub repo already has all preimages.
(b) Even if the disclosure were redacted, the secret space is
enumerable. Prover.toml.example and tests.nr confirm the secrets
are small ASCII-decimal integers (1..10). The total preimage space
tried during brute-force is effectively just single-digit integers,
which a laptop computes in milliseconds:
So even without the leak in the comment, the entropy is ~3.3 bits
(log2(10)) — trivially brute-forceable. main.nr checks knowledge of
the preimage but does not incorporate any location-bound or high-entropy
salt, so no physical treasure-finding effort is required to produce a
valid proof.
Likelihood: HIGH
The disclosure exists as of the contest snapshot and is part of the
in-scope repo; no adversarial reconnaissance is required.
Independently of the disclosure, a ~3.3-bit search is trivial.
Impact: HIGH
An attacker can generate valid ZK proofs for all 10 treasures
without any physical discovery and, combined with Finding 1 (the
double-claim bug), drain the entire 100 ETH reward pool in seconds
after deployment. Even without Finding 1 in play, the attacker
harvests 9 × 10 ETH = 90 ETH honestly, while the hunt organizer
loses the entire advertised reward budget and the physical
snorkelers get nothing.
The protocol's core economic and game-design guarantee — "only
people who find the treasure in the ocean can claim" — is
invalidated end-to-end.
Read contracts/scripts/Deploy.s.sol lines 14–15:
Attacker now has every secret.
For each secret s ∈ {1..10}, run the circuit's normal proof
generation path (off-chain):
All proofs are valid.
Submit each proof on-chain to claim() (choosing any attacker-
controlled recipient that is ≠ owner, ≠ address(0),
≠ address(this), ≠ msg.sender). Total take ≤ 9 × 10 = 90 ETH
(or 100 ETH when combined with Finding 1).
Brute-force-only variant (assuming the Deploy.s.sol comment were
removed in a future deployment): iterate candidate preimages
0..10⁶ through pedersen_hash([·]), match against the public
ALLOWED_TREASURE_HASHES. Runtime: on the order of seconds on a
laptop. Same on-chain consequence.
Remove the plaintext-secret comment from Deploy.s.sol. Even
for a demo, the comment teaches the wrong pattern and is directly
exploitable if the script is deployed as-is on mainnet.
Raise secret entropy to the field order. Use cryptographically
random 254-bit Field values (e.g. via
openssl rand -hex 32 mod BN254 field prime) as secrets. Store
secrets off-chain with the physical treasures (e.g. waterproof
QR-code cards); never commit them to the repo.
Bind secrets to the physical location. If the goal is "prover
was physically present at a specific GPS point at a specific time",
the proof must bind something only physical presence can reveal
(e.g. a hash of a beacon broadcast, a QR-code signature, a
rolling code). Pure pedersen_hash([random_secret]) still fails
to proof-of-location; it only proves knowledge. At minimum,
use a high-entropy secret so the proof is meaningful.
Consider adding an immutable salt to the circuit so that the same
10 preimages can't be reused across redeployments — each hunt has a
per-instance salt baked into its verifier. Combine with chain-ID /
contract-address domain separation.
This finding was identified and written up with the assistance of an
autonomous AI auditor (Anthropic Claude). Additional LLM cross-checks
used to rule out false positives.
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.