DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

JSON Injection in `tokenURI` Function (User Input Manipulation → Metadata Tampering)


Summary:

The tokenURI function constructs JSON metadata by directly concatenating user input (name, profileImage). This introduces a JSON injection vulnerability, allowing an attacker to manipulate the metadata by injecting special characters like double quotes (") or backslashes (\). Exploiting this, an attacker can alter NFT metadata, insert fake attributes, or disrupt NFT marketplaces relying on the token URI.


Vulnerability Details:

  • The function builds JSON using abi.encodePacked, inserting unescaped user input.

  • If an attacker supplies a malicious name or profileImage, they can break the JSON structure, inject arbitrary data, or modify metadata behavior.

  • JSON consumers (e.g., NFT marketplaces, wallets) will misinterpret the metadata, leading to incorrect attribute displays or spoofed profiles.


Code Snippet (Vulnerable Code):

function tokenURI(uint256 tokenId) public view override returns (string memory) {
if (ownerOf(tokenId) == address(0)) {
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(),
Base64.encode(
bytes(
abi.encodePacked(
'{"name":"',
profileName,
'", "description":"A soulbound dating profile NFT.", ',
'"attributes": [{"trait_type": "Age", "value": ',
Strings.toString(profileAge),
"}], ",
'"image":"',
imageURI,
'"}'
)
)
)
)
);
}

🚨 Risk: No escaping mechanism is applied, making it possible to inject unintended JSON elements.


Impact:

  1. Metadata Tampering: Attackers can inject fake attributes, misleading users and NFT platforms.

  2. Broken NFT Listings: Malformed JSON may cause token metadata to fail to load on marketplaces.

  3. Security Risks in External Platforms: Marketplaces parsing the JSON might be vulnerable to further exploits.

  4. Loss of Trust: Users may not trust metadata if attackers can spoof names or attributes.


Proof of Concept (PoC):

Attack Scenario – Injecting Fake Metadata Attributes

  1. Malicious User Calls mintProfile with Injected JSON Characters

    mintProfile('Evil"Profile", "attributes": [{"trait_type": "Age", "value": 100}], "image":"evil.com" } //', 25, "ipfs://malicious_image");
  2. Generated JSON (Incorrectly Parsed by Marketplaces)

    {
    "name": "Evil"Profile",
    "attributes": [{"trait_type": "Age", "value": 100}],
    "image":"evil.com" } //"
    }

    Effect:

    • The name field breaks the JSON format.

    • The attacker inserts fake attributes (Age = 100 instead of 25).

    • The remaining metadata could be ignored or misinterpreted.

Reference:

Recommended Mitigation:

Escape User Input Before Concatenating into JSON

Implement a JSON escaping function to properly encode special characters (", \, etc.):

✅ Apply Fix: Use Struct-Based Encoding

Instead of manual string concatenation, use abi.encode for structured JSON objects:

function tokenURI(uint256 tokenId) public view override returns (string memory) {
require(_exists(tokenId), "Token does not exist");
Profile memory profile = _profiles[tokenId];
bytes memory json = abi.encode(
'{"name":"', profile.name,
'", "description":"A soulbound dating profile NFT.", ',
'"attributes":[{"trait_type":"Age","value":', Strings.toString(profile.age), '}], ',
'"image":"', profile.profileImage, '"}'
);
return string(abi.encodePacked(_baseURI(), Base64.encode(json)));
}
Updates

Appeal created

n0kto Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_URI_injection_scam_underaged_bad_name_photo_etc

Scamming/phishing is not the protocol problem, that's a user mistake. NFT are unique, even if someone does a copy of your profile (which is also possible in web2), I consider it informational. Injection is a problem for the web2 part of the protocol, not a bug here. For the age, it depends on the countries law and future medicine. Anyways, that's more an ethical/political problem, not a bug.

Support

FAQs

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