SNARKeling Treasure Hunt

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

Duplicate treasure hash in circuit causes one reward (10 ETH) to be permanently locked

Author Revealed upon completion

Impact: One reward slot is permanently unclaimable, locking 10 ETH in the contract with no recovery path

Description

Only 9 unique treasures exist. MAX_TREASURES = 10 and REWARD = 10 ether, so the contract is funded with 100 ETH expecting 10 claimable treasures. The duplicate means only 9 can ever be claimed (or the same hash is claimed once and the duplicate slot is wasted).

The last two entries in ALLOWED_TREASURE_HASHES in main.nr are identical:

-961435057317293580094826482786572873533235701183329831124091847635547871092,
-961435057317293580094826482786572873533235701183329831124091847635547871092 // duplicate

Risk

Likelihood:

  • The duplicate exists at deployment, the 10th reward slot is unreachable from the moment the contract goes live with no action required by any party

  • The withdraw() function requires claimsCount >= MAX_TREASURES , with only 9 unique treasures this condition cannot be met through normal play, permanently blocking owner fund recovery too

Impact:

  • 10 ETH is permanently locked in the contract with no legitimate path to claim it

  • The owner cannot recover the locked ETH via withdraw() since claimsCount can never legitimately reach 10

Proof of Concept

1. Contract deployed with ALLOWED_TREASURE_HASHES indices [0..9]
2. Indices 8 and 9 share the same hash value
3. Participant claims index 8 — claimsCount = 1, claimed[hash] = true
4. No participant can claim index 9 (same hash, already marked claimed)
5. Maximum claimsCount reachable through unique treasures = 9
6. 10 ETH sits in the contract permanently unreachable
7. withdraw() requires claimsCount >= 10, condition never met legitimately

Recommended Mitigation

global ALLOWED_TREASURE_HASHES: [Field; 10] = [
1505662313093145631275418581390771847921541863527840230091007112166041775502,
-7876059170207639417138377068663245559360606207000570753582208706879316183353,
-5602859741022561807370900516277986970516538128871954257532197637239594541050,
2256689276847399345359792277406644462014723416398290212952821205940959307205,
10311210168613568792124008431580767227982446451742366771285792060556636004770,
-5697637861416433807484703347699404695743570043365849280798663758395067508,
-2009295789879562882359281321158573810642695913475210803991480097462832104806,
8931814952839857299896840311953754931787080333405300398787637512717059406908,
-961435057317293580094826482786572873533235701183329831124091847635547871092,
+ <unique_10th_treasure_hash> // @> replace with a unique hash derived from a unique secret
];

Support

FAQs

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

Give us feedback!