SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
Submission Details
Impact: high
Likelihood: high

Secret treasure values hardcoded in public deploy script allow anyone to generate valid ZK proofs and drain all rewards without finding any treasure

Author Revealed upon completion

Root + Impact

Description

  • The entire security model of the protocol relies on treasure secrets being unknown to participants. A valid ZK proof can only be generated by someone who knows the secret preimage of an allowed treasure hash. However, all 10 secret values are explicitly listed in plaintext in the public deploy script comments. Any person reading the repository can extract these secrets, generate valid ZK proofs off-chain, and claim all 10 rewards without physically finding any treasure.

  • The comment even confirms the mapping — secret 1 corresponds to hash 1505662313..., secret 2 to -7876059..., and so on. No physical treasure hunt is required.

// Script to deploy the TreasureHunt contract.
//
// The Verifier.sol is generated by Barrettenberg's Honk backend using `build.sh` script.
// For the upcoming snorkeling treausure hunt we place 10 treasures in the ocean in
// specified locations. Each treasure is associated with a unique hash (the "treasureHash") that serves as its identifier. To claim a treasure, a participant must find it and generate a ZK proof that they have found the treasure, without revealing its location. The proof is generated off-chain using the Noir circuit and Barrettenberg's Honk backend, and then submitted to the TreasureHunt contract on-chain. The contract verifies the proof using the HonkVerifier, and if valid, transfers the reward to the claimant.
// Secret Treasures for the snorkeling hunt (not revealed to the public):
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
// Treasures' hashes (revealed to the public, used as public inputs for the proof generation):
// 1505662313093145631275418581390771847921541863527840230091007112166041775502,
// -7876059170207639417138377068663245559360606207000570753582208706879316183353,
// -5602859741022561807370900516277986970516538128871954257532197637239594541050,
// 2256689276847399345359792277406644462014723416398290212952821205940959307205,
// 10311210168613568792124008431580767227982446451742366771285792060556636004770,
// -5697637861416433807484703347699404695743570043365849280798663758395067508,
// -2009295789879562882359281321158573810642695913475210803991480097462832104806,
// 8931814952839857299896840311953754931787080333405300398787637512717059406908,
// -4417726114039171734934559783368726413190541565291523767661452385022043124552,
// -961435057317293580094826482786572873533235701183329831124091847635547871092
// Note: The TreasureHunt contract requires funding at deployment, so we send 100 ETH
// in the constructor.
//
// Run with: `forge script Deploy.s.sol --rpc-url http://127.0.0.1:8545 --broadcast`
// in Anvil environment.
// Select appropriate RPC URL for the mainnet.

Risk

Likelihood:

  • Secrets are in a public GitHub repository — visible to anyone with the link

  • No technical skill required — secrets are plain integers (1 through 10)

  • Generating a ZK proof requires only the Noir toolchain (nargo prove) which is publicly available

Impact:

  • Any person can generate 10 valid ZK proofs off-chain using secrets 1–10

  • All 10 treasures can be claimed without any physical participation

  • Full 100 ETH drained before any legitimate finder can submit

  • The ZK proof system provides zero protection — the secret knowledge it is meant to protect is public

Proof of Concept

1. Read Deploy.s.sol from the public repository
2. Note secrets: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
3. For each secret i, set Prover.toml:
treasure = i
treasure_hash = ALLOWED_TREASURE_HASHES[i]
recipient = <attacker_address>
4. Run: nargo prove
5. Submit the proof to claim() on-chain
6. Repeat for all 10 secrets → 100 ETH drained

Recommended Mitigation

Remove all secret values from the deploy script immediately. Secrets must never appear in any file committed to a public repository. The deploy script should reference secrets via environment variables only.

For a real deployment, secrets should be stored in a secure off-chain vault and only used locally to generate proofs, never written to any file that enters source control.

- // Secret Treasures for the snorkeling hunt (not revealed to the public):
- // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
+ // Secrets are managed off-chain and must never be committed to version control.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!