SNARKeling Treasure Hunt

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

Event emits caller instead of recipient breaking the audit trail

Author Revealed upon completion

Root + Impact

Description

Line 111 emits the wrong address in the Claimed event:

// WRONG - emits the caller (msg.sender):
emit Claimed(treasureHash, msg.sender);
// Should be:
emit Claimed(treasureHash, recipient);

The event records WHO SUBMITTED THE TRANSACTION, not WHO RECEIVED THE MONEY.

Real-world example:

  • Bob (bounty hunter) finds treasure and gets ZK proof

  • Proof is bound to Alice (his friend who physically found the treasure)

  • Bob submits the claim transaction

  • Alice receives 10 ETH

Current broken behavior:

  • Event emits: Claimed(treasureHash, bob)

  • Off-chain system records: "Bob claimed treasureHash and received 10 ETH"

Reality:

  • Bob never received anything

  • Alice received 10 ETH

  • Event is completely wrong

Risk

Likelihood:

  • Occurs on every claim() call where msg.sender != recipient

  • This is a supported use case — the function accepts a separate recipient parameter

Impact:

  • Off-chain indexing shows wrong recipient data

  • Subgraphs and APIs return incorrect information

  • Audit trails and legal/compliance records are false

  • Forensic analysis is unreliable

  • Cannot verify who actually got paid from event logs alone

Proof of Concept

This test proves the event emits the caller instead of the recipient.
When msg.sender and recipient are different addresses, the emitted
event records the caller — not the address that actually received the 10 ETH.

function testExploit_WrongRecipientInEvent() public {
address eventShowsCaller = attacker1;
address actualRecipient = recipient;
// Current broken behavior - event shows caller not recipient:
vm.prank(eventShowsCaller);
vm.expectEmit(true, true, false, false);
emit Claimed(treasureHash, eventShowsCaller); // WRONG - shows caller
hunt.claim(proof, treasureHash, payable(actualRecipient));
// After fix should show:
// emit Claimed(treasureHash, actualRecipient); // CORRECT
}

Recommended Mitigation

The fix is a single one-word change on line 111. Replace msg.sender
with recipient so the event records the address that actually received
the reward, not the address that submitted the transaction.

- emit Claimed(treasureHash, msg.sender);
+ emit Claimed(treasureHash, recipient);

Support

FAQs

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

Give us feedback!