Website Security

XSS Prevention: Encode for the Output Context

Cross-site scripting begins when untrusted data becomes executable content. Learn contextual encoding, safe DOM APIs and CSP defence in depth.

Muhammad Azhar August 14, 2026 Reviewed August 21, 2026 3 min read

XSS occurs when untrusted data is interpreted as executable browser content. The correct defence depends on where data is inserted: HTML text, an attribute, a URL, CSS and JavaScript have different rules.

Prefer safe APIs

Use framework escaping and DOM properties such as textContent. Avoid building HTML strings from user data. When users genuinely need formatted HTML, apply a maintained sanitizer with a narrow allowlist.

Do not rely on input filtering alone

The same stored value may later appear in several output contexts. Encode at output for the actual context and validate input for business rules.

Add defence in depth

A nonce- or hash-based CSP can limit script execution if a bug remains. Mark session cookies HttpOnly, but remember XSS can still act through the victim's browser.

Test dangerous sinks

Review innerHTML, URL assignments, template escapes and client-side rendering after dependencies change.

URL handling needs protocol checks

Encoding a value does not make a dangerous javascript: URL safe. Parse and allow expected schemes before assigning user-controlled links. Treat SVG and rich-text uploads as active-content risks.

Framework escape hatches deserve review

APIs named like “dangerously set HTML,” raw templates or trusted types bypass normal escaping. Search for them during code review and require a documented sanitizer and data source.

Encode for the destination context

HTML text, attributes, URLs, CSS and JavaScript strings require different handling. Prefer template systems that escape by default and DOM APIs such as textContent. Avoid building markup with string concatenation, and sanitize rich HTML with a maintained library configured for the allowed use case.

Trace data from source to sink

Review URL parameters, stored profile fields, API responses and postMessage events. Dangerous sinks include innerHTML, raw template directives and script-generating APIs. Validate URL schemes before assigning user-controlled links; ordinary encoding does not make a javascript URL safe.

Add CSP as a containment layer and test representative payloads in a non-production environment. Fixing one reflected alert does not prove stored and DOM-based paths are safe.

Make safe output the default

HTML text, attributes, URLs, JavaScript and CSS have different parsing rules. One generic escape function cannot safely handle every destination. Prefer framework templates that escape by default, quote attributes and keep untrusted data out of executable contexts.

In browser code, use textContent for text and safe DOM methods for structure. Treat innerHTML, template injection and dynamic script creation as review points. If formatted user content is required, sanitize it with a maintained library and a narrowly defined allowlist.

Test stored and client-side paths

Follow input from request to storage to every later output. Stored XSS may appear in an administrator screen that the original submitter never sees. Client-side routing and URL fragments can create DOM XSS without a server-rendered page.

Add a restrictive CSP as damage reduction, not the primary fix. Review third-party scripts because they execute with the page's authority. Security tests should verify that representative payloads render as inert text and that legitimate rich content still works.

Review error pages, previews, emails and administrative tables as separate contexts. Content that is safe on the public page can become executable when copied into a dashboard built with different templates.

Sources and further reading