Santa's List

AI First Flight #3
Beginner FriendlyFoundry
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

`buyPresent` mints the gift NFT to the caller instead of `presentReceiver` — no gift reaches its recipient

Root + Impact

Description

  • Describe the normal behavior in one or more sentences

  • Explain the specific issue or problem in one or more sentences

### Summary
`buyPresent` delegates minting to `_mintAndIncrement`, which mints to `msg.sender`. The
`presentReceiver` argument therefore selects only whose tokens are burned, never who receives the
NFT. The function cannot perform the operation it is named and documented for; the misdelivery is
deterministic on every call and requires no attacker.
### Vulnerability Details
```solidity
/*
* @notice Buy a present for someone else. <-- :169
*/
function buyPresent(address presentReceiver) external {
i_santaToken.burn(presentReceiver);
_mintAndIncrement(); // -> _safeMint(msg.sender, ...) :181
}
function _mintAndIncrement() private {
_safeMint(msg.sender, s_tokenCounter++);
}
```
`_mintAndIncrement` is a private helper shared with `collectPresent`, where minting to `msg.sender`
is correct. `buyPresent` reuses it unchanged. The parameter names the beneficiary; the code makes
them the payer instead.
This is a distinct defect from H-04 on a distinct line. H-04 is `:173` charging the wrong party; this
is `:174` delivering to the wrong party. Stated rule **SL-6** — `buyPresent` *"trades `2e18` of
SantaToken for an NFT"* — is not honoured on either side of the trade.

Risk


### Impact
`buyPresent` cannot perform its documented function. No attacker is required and nothing needs to go
wrong — the misdelivery is deterministic on every call.
The PoC contains no adversary: four honest users each buy a present for the next in a round-robin.
Result: **4 presents minted, 0 reaching their recipient, 4 kept by the buyer**, and — because H-04 is
also live at the audited commit — 4 users charged by a transaction they did not send.
Rated Medium rather than High because, with H-04 fixed, the buyer pays and the buyer receives: no
value leaves the system and the buyer can forward the NFT themselves in one extra transaction. What
is lost is the protocol's advertised gifting capability, not funds.

Proof of Concept

**Proof of Concept** — `test/Claude/F06_MismatchedPayer.t.sol`
```bash
forge test --match-test test_F06 -vvv
```
```solidity
// Alice honestly buys a present for Bob. No attacker anywhere in this test.
vm.prank(alice);
list.buyPresent(bob);
assertEq(token.balanceOf(alice), 1e18, "the giver was not charged at all");
assertEq(token.balanceOf(bob), 0, "the RECIPIENT paid for their own gift");
assertEq(list.ownerOf(giftId), alice, "and the giver kept the present");
```
```
[PASS] test_F06_GivingAPresentTakesFromTheRecipient()
giver's balance before / after (wei): 1000000000000000000 1000000000000000000
recipient's balance before / after: 1000000000000000000 0
who the NatSpec says pays: the giver
who actually paid: the recipient
who the NatSpec says receives: the recipient
who actually received: the giver
[PASS] test_F06_NoGiftEverReachesItsRecipient()
gifts attempted: 4
presents that reached the recipient: 0
presents kept by the buyer: 4
users charged by someone else's tx: 4
```

Recommended Mitigation

Mint to the named beneficiary rather than reusing the collect-path helper:
```diff
function buyPresent(address presentReceiver) external {
i_santaToken.burn(msg.sender);
- _mintAndIncrement();
+ _safeMint(presentReceiver, s_tokenCounter++);
}
```
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 1 hour ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!