Safeguard
Security Guides•

Output encoding by context: HTML, attribute, JavaScript, CSS, URL

XSS defence depends on where data lands. Learn the encoding rule for HTML body, attributes, JavaScript, CSS and URLs, and why one escape function fails.

Safeguard Security Team
3 min read

Output encoding stops XSS only when it matches the place the data lands. HTML body text needs HTML entity encoding, attributes need quoting plus attribute encoding, JavaScript needs data inside quoted strings, CSS accepts values only in property positions, and URLs need percent encoding. One generic escape function cannot cover them all.

Why context matters

The browser parses a page in layers. The same string can be harmless in one layer and executable in another. OWASP's cheat sheet makes the point directly: encoding more characters as HTML entities does not remove the second context a value may also sit in.

The rules, one context at a time

HTML body. Convert &, less than, greater than, double quote and single quote into entities. Most template engines do this by default.

HTML attributes. Always quote the value, then apply an attribute encoder. Keep attribute names fixed, never taken from users. Event handler attributes such as onclick are unsafe for untrusted values, so attach handlers with addEventListener() instead.

JavaScript. Place data only inside a quoted string, using an encoder that protects both the string and the surrounding script block. Never build code from input. Avoid eval() and string versions of setTimeout() and setInterval(). When you return JSON, send Content-Type: application/json and not text/html.

CSS. Put variables only into a property value. Other CSS positions are unsafe. When setting styles from script, use a fixed property name and an allowlisted value.

URLs. Percent encode parameter values, not whole URLs. In JavaScript use encodeURIComponent() for a query value. For href or src, apply URL encoding first and attribute encoding second, and allow only http and https schemes.

A worked mistake

Consider a link built like this.

<a href="/search?q=USER_INPUT">results</a>

HTML entity encoding alone does not protect the query string. A value containing an ampersand or a space can add parameters or break out. The value needs URL encoding for the query, then attribute encoding for the surrounding HTML. Two contexts, two encoders.

Where frameworks leak

Modern frameworks encode by default, but each has an escape hatch. The OWASP page lists React's dangerouslySetInnerHTML, Angular's bypassSecurityTrust functions, Lit's unsafeHTML and Polymer's inner-h-t-m-l attribute. It also points out that React 19 blocking javascript: URLs does not replace validating URLs in your own code. Search your codebase for these names and review each hit.

What encoding cannot do

If users must submit rich text, encoding would show tags as plain text. In that case sanitize the HTML with a maintained library, as late as possible, and do not modify it afterwards. Patch the sanitizer often because bypasses appear regularly.

A review checklist

  1. For each place user data is printed, name the context.
  2. Confirm the encoder matches that context.
  3. Search for framework escape hatches and check the input to each.
  4. Confirm quotes around every attribute value.
  5. Add a Content Security Policy as a backstop, not as the main control.

Quick check

Is it safe to encode data when it is stored, instead of when it is displayed?

Encode at output. The right encoding depends on the context where the value is used, which is only known at display time.

Sources

Last reviewed: 19 October 2026.

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.