Normal behavior: mintProfile stores a user-chosen name and profileImage, and tokenURI should return an ERC721 metadata JSON in which those values appear strictly as DATA — the name as the value of the "name" field, the image as the value of the "image" field — regardless of what characters the user chose.
Specific issue: tokenURI builds the metadata by directly abi.encodePacked-concatenating the raw user strings into the JSON template with no escaping and no validation at mint time. Any " (or control character) in name/profileImage therefore terminates the surrounding JSON string early, and everything after it is emitted verbatim as JSON STRUCTURE inside the Base64 payload:
An attacker sets a name such as pwned","image":"http://evil.example/x.png","junk":". The produced metadata then contains an attacker-controlled "image" key that PRECEDES the legitimate one, plus arbitrary injected attributes. Consequences: (1) metadata/profile spoofing — a JSON parser that takes the first duplicate key renders the attacker's image instead of the real one; (2) arbitrary injected fields (fake attributes/traits); (3) on a dating frontend that renders name as HTML, classic markup/XSS. Because the injection is baked into the on-chain, immutable token metadata, every consumer of tokenURI is exposed.
Likelihood:
Any user can pick a crafted name/profileImage at mint with no restriction; deterministic and self-serve.
Impact:
Profile/metadata spoofing (attacker-controlled image and attributes) and client-side injection/XSS on naive frontends. Bounded to metadata/UI integrity rather than on-chain fund loss, hence Low.
test/AuditSoulbound.t.sol::test_6_metadata_json_injection (PASS): name pwned","image":"http://evil.example/x.png","junk":" produces metadata whose attacker "image" key precedes the legitimate one; the contract output equals Base64.encode(craftedJson) byte-for-byte.
Escape "/backslash/control characters in name and profileImage (or reject them), or build the JSON with a library that escapes.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.