DatingDapp

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

Unescaped profile strings can produce invalid NFT metadata JSON

Severity

Low

Likelihood

High

Root + Impact

tokenURI() inserts user-controlled strings into JSON metadata without escaping special characters, allowing malformed NFT metadata.

Description

  • The intended behavior is that tokenURI() should always return valid JSON metadata so wallets, marketplaces, and indexers can parse and display the NFT profile correctly.

  • Instead, profileName and imageURI are concatenated directly into the JSON string without escaping reserved characters such as " and \. As a result, a user can mint a profile whose metadata becomes invalid JSON and breaks downstream parsing or
    rendering.

function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
...
string memory profileName = _profiles[tokenId].name;
uint256 profileAge = _profiles[tokenId].age;
string memory imageURI = _profiles[tokenId].profileImage;
return string(
abi.encodePacked(
_baseURI(),
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
@> profileName,
'", ',
'"description":"A soulbound dating profile NFT.", ',
'"attributes": [{"trait_type": "Age", "value": ',
Strings.toString(profileAge),
"}], ",
'"image":"',
@> imageURI,
'"}'
)
)
)
)
);
}

Risk

Likelihood:

  • This occurs whenever a user mints a profile using unescaped reserved JSON characters in name or profileImage.

  • The issue is straightforward to trigger because both affected fields are fully user-controlled.

Impact:

  • The affected NFT metadata can become unparsable for wallets, marketplaces, and indexers.

  • This degrades NFT usability and display correctness without directly putting funds at risk.

Proof of Concept

The following test shows that including unescaped quote characters in user-controlled profile fields causes tokenURI() to return malformed JSON metadata.

function test_TokenURI_ReturnsInvalidJson_WhenProfileStringsContainQuotes() public {
// Mint a profile using strings that contain unescaped quote characters.
soulboundNFT.mintProfile("Jorx\"", 25, "foto\"");
// The first minted token has id 1 because the contract uses ++_nextTokenId.
string memory uri = soulboundNFT.tokenURI(1);
// Decode the Base64 metadata payload.
string memory base64Data = vm.parseJsonString(
string.concat('{"value":"', uri, '"}'),
".value"
);
// The decoded JSON becomes malformed because the quote characters
// are inserted into the metadata without escaping.
console2.log(base64Data);
}
Example decoded output:
{"name":"Jorx"", "description":"A soulbound dating profile NFT.", "attributes": [{"trait_type": "Age", "value": 25}],
"image":"foto""}

Recommended Mitigation

Validate or sanitize user-controlled strings before embedding them into JSON metadata. At minimum, reject characters that can break JSON string fields, such as " and \, before storing profile data.

+ function _validateJsonSafeString(string memory input) internal pure {
+ bytes memory data = bytes(input);
+ for (uint256 i = 0; i < data.length; i++) {
+ bytes1 char = data[i];
+ require(
+ char != 0x22 && // "
+ char != 0x5c, // \
+ "Invalid character in string"
+ );
+ }
+ }
function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(profileToToken[msg.sender] == 0, "Profile already exists");
+ _validateJsonSafeString(name);
+ _validateJsonSafeString(profileImage);
...
}
Updates

Lead Judging Commences

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