Snowman Merkle Airdrop

First Flight #42
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Impact: low
Likelihood: low
Invalid

Missing existence check in tokenURI() allows invalid metadata access

Root + Impact

Description

The tokenURI() function in Snowman.sol does not verify if a given tokenId exists before returning metadata. This allows users to query metadata for non-existent tokens, which can cause confusion in user interfaces and lead to potential misinformation or spoofing in off-chain systems.

Currently, tokenURI() returns a base64-encoded JSON string without checking if the tokenId has been minted. As a result, valid-looking metadata can be returned for invalid token IDs.

function tokenURI(uint256 tokenId) public view override returns (string memory) {
return string.concat(
"data:application/json;base64,",
Base64.encode(bytes(string.concat(
'{"name":"Snowman #',
tokenId.toString(),
...

Risk

Likelihood:

  • Reason 1 // Describe WHEN this will occur (avoid using "if" statements)

  • Reason 2

Impact:

  • Lack of error signaling for invalid token queries can cause confusion in user interfaces.

  • Potential for misinformation or spoofing in off-chain systems that rely on accurate metadata.

  • Inconsistent API behavior that breaks assumptions for users and developers.

Proof of Concept

Calling tokenURI(999999) on a contract that has minted only 3 tokens will still return a valid Base64 JSON response, despite the token not existing.
Example test:

try snowman.tokenURI(999999) {
revert("Test failed: tokenURI should revert for nonexistent token");
} catch Error(string memory reason) {
require(
keccak256(bytes(reason)) == keccak256(bytes("Snowman: URI query for nonexistent token")),
"Unexpected revert reason"
);
}

Recommended Mitigation

Add a check using _exists(tokenId) at the start of tokenURI() to ensure metadata is only returned for valid tokens. The function should revert with a clear error if the token does not exist.

function tokenURI(uint256 tokenId) public view override returns (string memory) {
+ require(_exists(tokenId), "Snowman: URI query for nonexistent token");
return string.concat(
"data:application/json;base64,",
Base64.encode(bytes(string.concat(
'{"name":"Snowman #',
tokenId.toString(),
Updates

Lead Judging Commences

yeahchibyke Lead Judge
3 months ago
yeahchibyke Lead Judge 3 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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