JavaScript Sanitizer API: Strip Malicious HTML

The JavaScript Sanitizer API provides a native browser mechanism to parse, filter, and strip cross-site scripting (XSS) vectors from dynamic HTML strings before they reach the Document Object Model (DOM). By moving sanitization directly into the browser rendering engine, it eliminates the need for heavy third-party libraries while ensuring untrusted content is safely converted into harmless DOM nodes according to a robust, predefined security baseline.

How the Sanitizer API Works

Traditional methods like element.innerHTML parse strings directly as active markup, executing any embedded JavaScript immediately. The Sanitizer API changes this workflow by acting as a secure intermediary layer during the parsing stage.

When provided with an untrusted HTML string, the browser: 1. Parses the string in an inert context: The browser parses the input into an in-memory document fragment where scripts cannot execute and external resources cannot load. 2. Walks the DOM tree: The Sanitizer inspects every node, tag, and attribute against its configuration rules. 3. Strips dangerous components: Malicious or non-compliant tokens are either completely removed (dropped) or stripped while keeping safe child nodes. 4. Appends safe nodes: The sanitized, harmless tree is inserted into the active DOM.

Default Protection Baseline

By default, an instance of the Sanitizer object applies a strict, secure configuration designed to eliminate known XSS execution paths without requiring manual rule definitions.

It automatically strips: * Executable script tags: Elements such as <script>, <object>, <embed>, and <iframe>. * Inline event handlers: Attributes like onclick, onerror, onload, and all other on* attributes. * Dangerous URI schemes: URLs utilizing javascript: or data: schemes within attributes such as href or src.

// Basic usage with default security settings
const sanitizer = new Sanitizer();
const untrustedInput = `<p>Safe text <script>alert("XSS")</script><img src="x" onerror="alert(1)"></p>`;

// Element method that parses and sanitizes automatically
document.getElementById("target").setHTML(untrustedInput, { sanitizer });

In the example above, the setHTML() method strips the <script> tag entirely and removes the onerror attribute from the <img> tag, resulting in a safe DOM output containing only <p>Safe text <img src="x"></p>.

Customizing Configuration Rules

Developers can customize the filtering logic to suit specific application needs using configuration objects. The API provides granular controls to allow, block, or drop specific elements and attributes:

// Custom sanitizer configuration
const customSanitizer = new Sanitizer({
  allowElements: ["b", "i", "em", "strong", "a"],
  allowAttributes: { "href": ["a"] },
  dropElements: ["style"]
});

const userComment = `<b>Formatted text</b> <style>body { display: none; }</style> <a href="https://example.com" onclick="stealData()">Link</a>`;

document.getElementById("comment-box").setHTML(userComment, { sanitizer: customSanitizer });

In this case, the <style> tag and its inner CSS rules are dropped entirely, the <b> and <a> elements are preserved, and the onclick handler is stripped from the link.

Direct Parsing with sanitizeFor

For scenarios where the sanitized content must be inspected or manipulated before DOM insertion, the API provides the sanitizeFor() method. It takes a target tag name and untrusted markup, returning an inert HTMLElement containing the sanitized tree.

const sanitizer = new Sanitizer();
const cleanFragment = sanitizer.sanitizeFor("div", untrustedInput);

// Safe to read child nodes or attach conditionally
console.log(cleanFragment.innerHTML);

By shifting sanitization to the browser core, the Sanitizer API standardizes defensive programming, minimizes performance overhead, and systematically protects web applications from DOM-based XSS attacks.