Safeguard
Application Security•

ASVS 5.0 V1.2.3: Prevent JavaScript and JSON Injection

ASVS V1.2.3 requires encoding when you build JavaScript or JSON dynamically. Learn why string concatenation fails and how to embed data safely.

Safeguard Security Team
3 min read

ASVS 5.0 V1.2.3 (Level 1) says that whenever you build JavaScript content, including JSON, from dynamic data, you must use output encoding or escaping so that data cannot change the structure of the script or document. In practice: serialize with a real JSON encoder and never assemble script by joining strings.

Why it matters

Consider a page that does var user = " plus a name plus ";. A name containing a quote and a semicolon ends the string and starts new code. JSON built by hand has the same problem: a value with a quote or a backslash can add keys or break parsing for the consumer, and a value containing a closing script tag can end an inline script block early when JSON is embedded in HTML.

How to implement it

Serialize with the language's JSON library, and when embedding JSON in an HTML page, also escape characters that can close the script element.

import json
from markupsafe import Markup

def json_for_html(obj) -> Markup:
    s = json.dumps(obj)
    s = (s.replace("<", "\\u003c")
          .replace(">", "\\u003e")
          .replace("&", "\\u0026")
          .replace("
", "\\u2028")
          .replace("
", "\\u2029"))
    return Markup(s)

An even safer pattern avoids inline script data entirely. Put the data in a data- attribute, or in a script tag with type application/json, and read it with JSON.parse. Frameworks such as Jinja2 ship a tojson filter that does the escaping for you.

For API responses, return Content-Type: application/json and use the framework serializer, never string formatting.

res.json({ name: userName, note: userNote });   // not: res.send('{"name":"' + userName + '"}')

How to test it

Set a field value to "};alert(1);//, to </script><script>alert(1)</script> and to a string with a backslash and quote. Load every page that embeds it and confirm no script runs and the data appears literally. For APIs, parse the response with a strict JSON parser and confirm the keys match the schema exactly.

Common mistakes

  • Embedding user data in onclick attributes or inline handlers.
  • Using HTML encoding inside a script block, which is the wrong context.
  • Forgetting the line separator characters in older environments.
  • Using eval to read JSON. Use JSON.parse.

Where this goes wrong in practice

Single page applications often receive initial state from the server as a script block holding a JSON object. Developers write the object with string formatting because it looks harmless. A user profile with a display name of </script><script>alert(1)</script> ends the block early and runs the attacker's script for every visitor of that profile, which is a stored cross site scripting flaw.

The fix is mechanical: escape the characters that can end or alter the block when the JSON is placed in HTML, as the helper above does, or avoid inline data completely and fetch it with an API call that returns application/json. Content Security Policy with nonces adds a second layer, because injected script without the nonce will not run.

Server side JSON building needs the same care. Joining strings to make a JSON request body for another service means a value with a quote can add fields such as "isAdmin": true. Always build an object and serialize it.

Quick check

What is the safest way to pass server data to client script?

Serialize with a JSON library and place it in a data attribute or a JSON script block, then parse it with JSON.parse.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.