Summary: The tokenURI
function contains an incorrect token existence check that can never be triggered, resulting in unreachable code.
Description: The Snowman contract includes a check in the tokenURI
function that attempts to verify whether a token exists before returning its URI. However, this check is implemented incorrectly. The code compares the result of ownerOf(tokenId)
against address(0)
to determine if the token exists.
The fundamental issue is that OpenZeppelin's ERC721 implementation never returns address(0)
from the ownerOf
function. Instead, when queried for a non-existent token, the ownerOf
function reverts with a custom error. As a result, the condition ownerOf(tokenId) == address(0)
can never be true, and the custom error ERC721Metadata__URI_QueryFor_NonExistentToken()
is never thrown.
The vulnerability cannot be directly exploited to cause harm, but it represents a misunderstanding of how the underlying ERC721 contract works and creates misleading code that suggests functionality that does not actually work.
Step-by-step Analysis:
The tokenURI
function attempts to check token existence by comparing ownerOf(tokenId)
to address(0)
.
However, in OpenZeppelin's ERC721 implementation, ownerOf
reverts with a custom error when called for a non-existent token.
The execution never reaches the comparison because it reverts earlier in the call stack.
Thus, the custom error ERC721Metadata__URI_QueryFor_NonExistentToken()
is dead code that can never be triggered.
The function has redundant logic since the ownerOf
function already handles the token existence check.
Severity Classification:
Impact: Medium - While not directly exploitable, it indicates a misunderstanding of the underlying contract's behaviour. This could lead to confusion for developers and auditors and potentially mask other issues.
Likelihood: High - This issue is present in all calls to tokenURI
with non-existent tokens, but the impact is limited to code quality rather than functionality.
File Name: src/Snowman.sol
Code:
Recommendation:
Either remove the redundant check entirely (since OpenZeppelin's ownerOf
already handles this) or replace it with a check that actually works, such as using the _exists
function.
Recommended Code Fix:
Option 1: Remove the redundant check (preferred):
Option 2: Use _exists
for an explicit check:
Either fix would ensure the code accurately reflects the intended functionality and removes the dead code.
Proof of Concept:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.