Problem
Serialize.tryToJSONString wraps string values in double quotes without escaping the content:
// cadence/contracts/utils/Serialize.cdc:30
case Type<String>():
return String.join(["\"", value as! String, "\"" ], separator: "")
", \, and control characters (U+0000–U+001F) pass through unescaped, which violates RFC 8259 §7. The same gap applies to the Type<String?>() (line 32) and Type<Character>() (line 34) cases, and to dictionary keys in dictToJSONString (line 120), which are serialized through the same helper.
Impact
SerializeMetadata.serializeNFTMetadataAsURI is the fallback tokenURI path for every NFT that does not resolve MetadataViews.EVMBridgedMetadata (see handleDefaultNFTToEVM in FlowEVMBridge.cdc). A single newline, quote, or backslash in a Display description or trait value makes the entire metadata document unparseable — block explorers, wallets, and marketplaces silently render no metadata at all.
- The same serializer derives
contractURI during onboarding (FlowEVMBridgeUtils.cdc:414,430). The bridged ERC721 template exposes no setContractURI, so a corrupted contractURI is permanent for that collection. Every newly onboarded collection with such characters in its NFTCollectionDisplay is at risk until this is fixed.
- The unescaped code is present in the currently deployed mainnet
Serialize contract.
Example — an NFT description containing a raw line feed serializes to:
data:application/json;utf8,{"name": "Example NFT #42", "description": "Line one
Line two", "image": "https://example.com/42.png"}
A strict parser rejects this: json.JSONDecodeError: Invalid control character at: line 1 column 53 (char 52).
Proposed fix
- Add an
escapeJSONString(_ s: String): String helper to Serialize.cdc that escapes \, ", and control characters (\n, \r, \t, \b, \f, and \u00XX for the remaining U+0000–U+001F range).
- Apply it in the
String, String?, and Character cases of tryToJSONString and to keys in dictToJSONString.
Because the bridge rewrites tokenURI on every Cadence→EVM bridge, the fix retroactively repairs per-NFT metadata for affected collections on their next bridge round-trip — no project-side changes required. Already-onboarded collections with a corrupted contractURI remain unrecoverable, which is why this should be fixed promptly.
Acceptance criteria
Problem
Serialize.tryToJSONStringwraps string values in double quotes without escaping the content:",\, and control characters (U+0000–U+001F) pass through unescaped, which violates RFC 8259 §7. The same gap applies to theType<String?>()(line 32) andType<Character>()(line 34) cases, and to dictionary keys indictToJSONString(line 120), which are serialized through the same helper.Impact
SerializeMetadata.serializeNFTMetadataAsURIis the fallbacktokenURIpath for every NFT that does not resolveMetadataViews.EVMBridgedMetadata(seehandleDefaultNFTToEVMinFlowEVMBridge.cdc). A single newline, quote, or backslash in aDisplaydescription or trait value makes the entire metadata document unparseable — block explorers, wallets, and marketplaces silently render no metadata at all.contractURIduring onboarding (FlowEVMBridgeUtils.cdc:414,430). The bridged ERC721 template exposes nosetContractURI, so a corruptedcontractURIis permanent for that collection. Every newly onboarded collection with such characters in itsNFTCollectionDisplayis at risk until this is fixed.Serializecontract.Example — an NFT description containing a raw line feed serializes to:
A strict parser rejects this:
json.JSONDecodeError: Invalid control character at: line 1 column 53 (char 52).Proposed fix
escapeJSONString(_ s: String): Stringhelper toSerialize.cdcthat escapes\,", and control characters (\n,\r,\t,\b,\f, and\u00XXfor the remaining U+0000–U+001F range).String,String?, andCharactercases oftryToJSONStringand to keys indictToJSONString.Because the bridge rewrites
tokenURIon every Cadence→EVM bridge, the fix retroactively repairs per-NFT metadata for affected collections on their next bridge round-trip — no project-side changes required. Already-onboarded collections with a corruptedcontractURIremain unrecoverable, which is why this should be fixed promptly.Acceptance criteria
cadence/tests/serialize_tests.cdccovering quotes, backslashes, newlines/CR/tab, and other control characters, validating output against a strict JSON parsercadence/tests/serialize_metadata_tests.cdc: an NFT with a multi-line description produces a parseable JSON data URISerializeon testnet and mainnet (tracked separately if preferred)