SNARKeling Treasure Hunt

First Flight #59
Beginner FriendlyGameFiFoundry
100 EXP
View results
Submission Details
Severity: low
Valid

(LOW) `Funded` event omits the sender, so you cannot tell whether a deposit came through `fund()` or `receive()`

Location: contracts/src/TreasureHunt.sol:45 (declaration); emitted at lines 240 and 288

Description

The event has no from field:

event Funded(uint256 amount, uint256 newBalance);

Because receive() is not owner restricted, deposits can come from any address. Downstream accounting that subscribes to Funded cannot tell owner top ups from unsolicited stranger deposits.

Risk

Likelihood: High happens on every deposit.

Impact: Low. Accounting noise; dashboards and indexers cannot attribute funding correctly.

Proof of Concept

event Funded(uint256 amount, uint256 newBalance);
function test_FundedEventOmitsSender() public {
address stranger = makeAddr("stranger");
vm.deal(stranger, 1 ether);
// No `from` topic to filter on, so the subscriber cannot distinguish
// this stranger deposit from an owner-initiated fund() call.
vm.expectEmit(false, false, false, true, address(hunt));
emit Funded(1 ether, address(hunt).balance + 1 ether);
vm.prank(stranger);
(bool ok, ) = address(hunt).call{value: 1 ether}("");
assertTrue(ok);
}

Run:

forge test --match-test test_FundedEventOmitsSender -vv

The test passes the event contains no sender data.

Recommended Mitigation

Add an indexed from topic:

- event Funded(uint256 amount, uint256 newBalance);
+ event Funded(address indexed from, uint256 amount, uint256 newBalance);
...
- emit Funded(msg.value, address(this).balance);
+ emit Funded(msg.sender, msg.value, address(this).balance);
Updates

Lead Judging Commences

s3mvl4d Lead Judge 18 days ago
Submission Judgement Published
Validated
Assigned finding tags:

nonowner can fund

Although the explicit `fund()` function is restricted to the owner via `require(msg.sender == owner, "ONLY_OWNER_CAN_FUND")`, the contract also implements a permissive `receive()` function that accepts arbitrary ETH sent directly to the contract and emits the same Funded event without any sender check. This means a non-owner cannot use the `fund()` entrypoint itself, but can still increase the contract balance simply by transferring ETH to the contract address. This is an access-control inconsistency between the documented admin funding path and the actual fallback behavior.

Support

FAQs

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

Give us feedback!