← Blog
Data FormatsApril 29, 20257 min

JSON String Escaping: Characters, Edge Cases, and Common Mistakes

Which characters must be escaped in JSON strings, how Unicode escapes work, and how improper handling leads to bugs or security issues.

Why JSON Needs String Escaping

JSON strings are delimited by double quotes. Any character inside a string that could be misinterpreted as JSON structure — or that cannot be represented literally — must be escaped with a backslash sequence. The JSON specification (RFC 8259) defines exactly which characters require escaping.

Required Escape Sequences

"   → double quote (end-of-string delimiter)
\   → backslash (escape character itself)
/   → forward slash (optional but valid)
\b  → backspace (U+0008)
\f  → form feed (U+000C)
\n  → line feed / newline (U+000A)
\r  → carriage return (U+000D)
\t  → horizontal tab (U+0009)

Control characters (U+0000 to U+001F) must be escaped — they cannot appear literally in JSON strings. This includes null bytes, newlines, and tabs.

Unicode Escape Sequences

Any character can be escaped using \uXXXX where XXXX is a four-digit hex code point:

"\u0041"     → "A"
"\u00e9"     → "é"
"\u4e2d\u6587" → "中文"
"\u0000"     → null byte (U+0000)

For characters outside the Basic Multilingual Plane (above U+FFFF, like emoji), JSON uses surrogate pairs: two \uXXXX sequences that together encode the character.

// 😀 (U+1F600) as a JSON surrogate pair
"\uD83D\uDE00"

Escaping in JavaScript

JSON.stringify() handles escaping automatically. It is the correct way to produce JSON strings from user input:

const userInput = 'He said "hello"\nNew line here';
const json = JSON.stringify(userInput);
// '"He said \"hello\"\nNew line here"'

// NEVER concatenate strings manually:
const bad = '{"name": "' + userInput + '"}'; // BROKEN with special chars

Unescaping JSON Strings

To convert a JSON-encoded string back to its raw value, use JSON.parse():

const escaped = '"Hello\\nWorld"'; // the raw JSON string value
JSON.parse(escaped); // → 'Hello\nWorld'

Double-Encoding: A Common Mistake

Double-encoding happens when a string that is already JSON-escaped gets escaped again. The result looks garbled:

// First encoding
const once = JSON.stringify('hello "world"');
// '"hello \"world\""'

// Double-encoded (wrong)
const twice = JSON.stringify(once);
// '"\"hello \\\"world\\\"\""'

This happens when you store a JSON string in a database and then serialize the containing object again. The fix: parse before re-serializing, or store the raw value rather than the JSON-encoded version.

JSON Injection

If user input is interpolated into a JSON string without proper escaping, an attacker can break out of the string context and inject arbitrary JSON structure:

// Vulnerable template literal
const payload = `{"username": "${userInput}"}`;

// Attacker input: admin", "admin": true, "x": "
// Result:
// {"username": "admin", "admin": true, "x": ""}
// ↑ injected "admin": true property

Always use JSON.stringify() to build JSON. Never build JSON by string concatenation or template literals with unescaped values.

forward slash: Optional Escaping

The forward slash / may be escaped as \/ in JSON but is not required to be. Some JSON encoders escape it to prevent </script> sequences from closing script tags when JSON is embedded in HTML:

// Safe for embedding in <script> tags
{"url": "https:\/\/example.com\/path"}

// vs unescaped (still valid JSON)
{"url": "https://example.com/path"}

Try it yourself

Escape raw text into a JSON-safe string or unescape a JSON string back to plain text.

Open JSON Escape →