JSON escaping is a syntax operation for representing a string inside a JSON document. It is not encryption, URL encoding, Base64, HTML escaping, SQL quoting, or a general injection defense. In most applications, the safest operation is to pass values to a standard serializer and let the parser consume the result at the correct boundary.

Key Takeaways

  • Inside a JSON string, quotation marks, backslashes, and every control character from U+0000 through U+001F must be represented with valid escapes.
  • \/ is permitted but not required by JSON. Unicode characters may appear literally or as \uXXXX escapes, subject to the parser and transport.
  • JSON.stringify("text") returns a complete JSON string literal including its surrounding quotes; it is not merely an unquoted escaped fragment.
  • Nested JSON should normally remain a nested object. Stringify it only when the receiving protocol explicitly requires a JSON string.
  • Use standard serializers and parsers. Manual replacement, eval, and ad-hoc “unescape” logic are fragile.
  • Escaping makes syntax valid; it does not authorize input, sanitize HTML, prevent SQL injection, validate a schema, or make untrusted content safe to execute.

JSON String Grammar

A JSON string is surrounded by " characters. The unescaped characters inside it cannot include " or \, and control characters U+0000–U+001F must not appear literally. The short escapes are:

Character or value JSON spelling Requirement
quotation mark \" required inside a string
reverse solidus \\ required inside a string
backspace \b required as an escape
form feed \f required as an escape
line feed \n required as an escape
carriage return \r required as an escape
horizontal tab \t required as an escape
other U+0000–U+001F \u00XX required as an escape
solidus / \/ optional; / is also valid

The JSON grammar does not require every non-ASCII character to be escaped. \uXXXX represents one UTF-16 code unit; characters outside the Basic Multilingual Plane may be represented as a surrogate pair such as \uD83D\uDE00. A parser must validate its Unicode behavior and reject malformed sequences according to its API.

Escape Is Not Encode

Operation Purpose Example
JSON escaping Represent syntax-sensitive characters in a JSON string "\"
JSON serialization Convert a value into a complete JSON document/literal object → {"id":1}
URL encoding Represent data in a URL component space → %20
Base64 Represent bytes as ASCII text bytes → SGVsbG8=
HTML escaping Represent text safely in an HTML context <&lt;
SQL parameters Bind values to a database statement driver parameter, not string concatenation

Applying one operation does not perform the others. The correct operation is determined by the next parser or interpreter that will consume the data.

Serialize Values with Standard Libraries

javascript
const value = {
  message: 'He said "hello".',
  lines: "first\nsecond",
  unicode: "世界 😀",
};

const documentText = JSON.stringify(value);
console.log(documentText);
const roundTrip = JSON.parse(documentText);

The result of JSON.stringify("hello") is "hello" including quotes. If a protocol expects a JSON document, pass the complete result. If it expects a JavaScript string value, do not strip quotes unless you have a precise reason and a separate contract.

python
import json

value = {"message": 'He said "hello".', "lines": "first\nsecond"}
document_text = json.dumps(value, ensure_ascii=False)
round_trip = json.loads(document_text)

In Python, ensure_ascii=False keeps non-ASCII characters readable; the JSON remains valid UTF-8 when the transport is configured accordingly. ensure_ascii=True is a representation choice, not a security improvement.

Nested JSON: Object or String?

Prefer a nested object when the receiver understands JSON:

javascript
const structured = {
  payload: { name: "Ada", enabled: true },
};

Use a JSON string only when the outer protocol explicitly models payload as text:

javascript
const embedded = {
  payload: JSON.stringify({ name: "Ada", enabled: true }),
};

const outerText = JSON.stringify(embedded);
const parsedOuter = JSON.parse(outerText);
const innerValue = JSON.parse(parsedOuter.payload);

Every additional string layer adds another serialization boundary and more backslashes. Do not repeatedly escape data to “make it safer”; define the number of layers and parse exactly once at each boundary.

Unescaping and Validation

Do not write an unescape function by replacing \" and \\ in arbitrary text. A valid JSON string literal should be parsed by a JSON parser:

javascript
const literal = '"Hello \\"world\\"\\n"';
const value = JSON.parse(literal);

try {
  JSON.parse(userSuppliedText);
} catch (error) {
  // Reject malformed JSON; do not guess how to repair it.
}

If an API provides an unquoted escape fragment, wrap it only under a contract that guarantees it is a valid JSON string body, then parse the constructed literal and enforce a size limit. Never use eval or Function to interpret it.

Parsing validates syntax, not meaning. Apply a schema, type, size, depth, authorization, and business-policy check after parsing. A string containing HTML, SQL, a shell command, or a prompt remains untrusted data after JSON parsing.

For a disposable test string, the JSON Escaper can show one escape or unescape layer in the browser. It is a diagnostic aid, not a replacement for a serializer at the application boundary. See the JSON definition for the value model and grammar context.

Multi-Language Boundaries

Go

Use encoding/json and check errors. Avoid slicing the marshaled output to remove quotes unless the value is known to be a JSON string and the contract explicitly requires the string body.

go
package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	value := map[string]string{"message": "He said \"hello\""}
	data, err := json.Marshal(value)
	if err != nil {
		panic(err)
	}
	fmt.Println(string(data))
}

Java

Use one JSON library consistently, such as Jackson, and distinguish a JSON tree/value from its serialized text. Configure unknown-field, duplicate-field, numeric, and Unicode policies explicitly where the application needs them.

java
ObjectMapper mapper = new ObjectMapper();
String text = mapper.writeValueAsString(Map.of("message", "He said \"hello\""));
JsonNode value = mapper.readTree(text);

The imports and dependency version belong to the build configuration; do not mix independent JSON object models in one example without an adapter.

Context-Specific Security

HTTP APIs

Serialize the request object once and send it with the correct Content-Type. Do not concatenate user input into a JSON source string. The server must still authenticate, authorize, validate a schema, enforce limits, and reject unexpected fields.

Databases

Store JSON through a database driver’s typed JSON parameter or a prepared statement. JSON escaping does not protect a SQL statement assembled by concatenation. Use the database’s JSON functions for querying and validate retention, access, and logging.

HTML and JavaScript

JSON escaping is not HTML escaping. Embedding JSON in a <script> block or HTML attribute requires a context-aware safe serialization strategy, CSP, and correct delimiter handling. Do not place untrusted values into executable JavaScript by string concatenation.

URLs and Headers

JSON text placed in a URL query, path, or HTTP header requires the rules of that context as well. URL-encode the component after serialization when appropriate, and enforce length and character policies.

Logs

JSON.stringify can make a structured log valid, but it does not remove secrets or personal data. Apply field-level redaction and bounded serialization before logging.

Common Mistakes

Manual Replacement

Replacing only quotation marks misses backslashes and control characters, and replacement order can double-escape existing sequences. Use the standard serializer.

Double Escaping

An already serialized JSON string is data, not a value to serialize again unless a second protocol layer requires it. Track whether a variable is a native value, a JSON document, or a JSON string literal.

Confusing Unicode Escapes with Sanitization

Changing < to \u003C may help in a narrowly defined JavaScript embedding strategy, but it does not validate a schema, remove an unsafe URL, or authorize content. Choose a context-specific defense.

Accepting Non-Standard Values

JSON does not contain NaN, Infinity, undefined, comments, or trailing commas in its standard grammar. Libraries may offer extensions; enable them only when the protocol explicitly allows them and document interoperability consequences.

A Verification Checklist

  1. Identify the next parser or interpreter and use its encoding rules.
  2. Serialize values with a standard library; do not hand-build JSON.
  3. Keep nested data structured unless a string layer is required.
  4. Test quotes, backslashes, each control character, Unicode, surrogate pairs, empty strings, null, large values, and malformed input.
  5. Parse the output and compare the resulting value under the intended numeric and Unicode policy.
  6. Enforce byte, depth, member, array, and nesting limits.
  7. Apply schema validation, authorization, redaction, and context-specific output encoding.
  8. Record parser/library versions for reproducible behavior.

Frequently Asked Questions

Does every non-ASCII character need \uXXXX?

No. JSON permits Unicode characters directly when the transport encoding supports them. Escaping them can improve ASCII-only transport compatibility, but it does not add confidentiality or integrity.

Is / required to be escaped as \/?

No. Both / and \/ are valid JSON string representations. Some historical embedding strategies used \/, but do not add it as a general security guarantee.

Why are there more backslashes at each nesting level?

Each JSON string layer must escape the backslashes that represent the previous layer’s quotes and escapes. Avoid unnecessary layers and parse one layer at a time.

Does JSON escaping prevent injection?

It prevents a value from breaking the JSON syntax when serialized correctly. It does not prevent SQL, HTML, shell, URL, prompt, or business-logic injection in another context. Validate and authorize separately.

Can I repair malformed JSON by replacing escape sequences?

Usually not safely. Reject malformed input and return a precise parse error, or use a deliberately specified tolerant parser with documented data-loss behavior. Silent repair can change the user’s data.

Primary Sources

Conclusion

Correct JSON escaping means representing a value according to JSON’s grammar at one specific boundary. Use standard serialization, preserve structure when possible, avoid unnecessary nesting, parse rather than “unescape” by substitution, and apply the defenses required by the next context. Syntax correctness is necessary, but it is only one part of safe data handling.