DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

[H-2] Malformed tokenURI and Invalid Existence Check in SoulboundProfileNFT

Root + Impact

Description

  • SoulboundProfileNFT.tokenURI should return valid metadata for existing tokens and reject non-existent token requests.

  • The contract uses ownerOf(tokenId) == address(0) to detect missing tokens and omits the required data:application/json;base64, prefix for on-chain JSON metadata.

function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
@> if (ownerOf(tokenId) == address(0)) {
revert ERC721Metadata__URI_QueryFor_NonExistentToken();
}

Risk

Likelihood:

  • Calls to tokenURI for non-existent token IDs revert unexpectedly instead of returning a clean error path.

  • Wallets and marketplaces will fail to parse metadata because the returned string is Base64 data without the required URI prefix.

Impact:

  • NFT metadata becomes inaccessible, breaking wallets, explorers, and token display.

  • Marketplace compatibility is lost, and end users cannot view the profile metadata.

Proof of Concept

The following test demonstrates that ownerOf reverts for non-existent tokens instead of returning address(0), and the metadata lacks the proper data URI prefix:

// tokenURI will revert for a missing token instead of returning metadata
soulboundProfileNFT.tokenURI(9999); // Reverts because ownerOf(9999) reverts for non-existent token
// Also, the returned string is missing the data URI prefix, making it unparseable:
// Expected: "data:application/json;base64,eyJ..."
// Actual: "eyJ..." (Base64 only, no prefix)

Recommended Mitigation

Replace the existence check with the proper _exists internal function and prepend the data URI prefix to the Base64 output:

- if (ownerOf(tokenId) == address(0)) {
+ if (!_exists(tokenId)) {
revert ERC721Metadata__URI_QueryFor_NonExistentToken();
}
string memory profileName = _profiles[tokenId].name;
uint256 profileAge = _profiles[tokenId].age;
string memory imageURI = _profiles[tokenId].profileImage;
return string(
abi.encodePacked(
- _baseURI(),
+ "data:application/json;base64,",
Base64.encode(
bytes(
abi.encodePacked(
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 7 hours 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!