The Hidden Cost of Sanitization: How Secure Parsing Can Introduce New XSS Attack Surfaces

Ashish Kataria (Security Architect Engineer · Synacor)

Nullcon Goa 2026 · Day 1

Overview

Ashish Kataria's talk, "The Hidden Cost of Sanitization: How Secure Parsing Can Introduce New XSS Attack Surfaces," delivered at Nullcon, challenges the pervasive assumption that employing sanitization libraries automatically eliminates the risk of Cross-Site Scripting (XSS) vulnerabilities. Kataria, a Security Architect Engineer at Synopsys, presents a compelling argument that modern sanitization techniques, particularly when deployed in multi-stage pipelines, can inadvertently create new XSS attack surfaces rather than merely mitigating existing ones. His research delves into a novel class of XSS vulnerabilities that arise from fundamental mismatches in how different parsers—specifically, security sanitizers and web browsers—interpret and transform HTML content.

Watch on YouTube

Visual summary for The Hidden Cost of Sanitization: How Secure Parsing Can Introduce New XSS Attack Surfaces by Ashish Kataria
Visual summary for The Hidden Cost of Sanitization: How Secure Parsing Can Introduce New XSS Attack Surfaces by Ashish Kataria

Key moments

  1. 0:00 Introduction: Sanitizers and new XSS attack surfaces
  2. 2:40 Understanding the browser vs. sanitizer parsing mismatch
  3. 4:10 Challenging assumption: Sanitizers can introduce XSS
  4. 6:00 Demonstration: Attribute context injection bypasses sanitizer
  5. 8:00 Historical overview: Evolution of XSS prevention methods

The Hidden Cost of Sanitization: How Secure Parsing Can Introduce New XSS Attack Surfaces

Speakers: Ashish Kataria, Security Architect Engineer, Synopsys

Conference: Nullcon

YouTube: https://www.youtube.com/watch?v=BJCgSLGq308

Overview

Ashish Kataria's talk, "The Hidden Cost of Sanitization: How Secure Parsing Can Introduce New XSS Attack Surfaces," delivered at Nullcon, challenges the pervasive assumption that employing sanitization libraries automatically eliminates the risk of Cross-Site Scripting (XSS) vulnerabilities. Kataria, a Security Architect Engineer at Synopsys, presents a compelling argument that modern sanitization techniques, particularly when deployed in multi-stage pipelines, can inadvertently create new XSS attack surfaces rather than merely mitigating existing ones. His research delves into a novel class of XSS vulnerabilities that arise from fundamental mismatches in how different parsers—specifically, security sanitizers and web browsers—interpret and transform HTML content.

The core of the problem lies in the inherent tension between a browser's aggressive desire to render any HTML, often attempting to repair malformed markup, and a sanitizer's strict objective to enforce security policies. While sanitizers aim to produce "safe" HTML, the subsequent interpretation by a browser or another sanitizer in a complex pipeline can lead to a "semantic drift," where the intended secure structure is mutated into an exploitable form. This talk is crucial for web developers, security engineers, and architects who rely on sanitization libraries like OWASP HTML Sanitizer, AntiSamy, and DOMPurify, as it exposes the subtle yet critical pitfalls of these widely adopted security measures, urging a more nuanced and context-aware approach to input validation and content transformation.

Background

▶ Watch: Introduction: Sanitizers and new XSS attack surfaces (0:00)

The landscape of XSS prevention has undergone significant evolution over the past 15 years, yet XSS remains one of the most prevalent web application vulnerabilities. Initially, around 2005-2010, the industry's approach was rudimentary, focusing on blacklisting malicious characters and common patterns like <script> tags. This era saw simple bypasses through obfuscation and alternative tag usage, as exemplified by the speaker's anecdote of stealing cookies from Orkut users by injecting JavaScript. As attackers adapted, so did defenses. From 2010-2015, the paradigm shifted towards allow-listing specific safe HTML tags and events while filtering dangerous attributes.

Post-2015, modern content pipelines emerged, incorporating sophisticated techniques such as markup normalization, regex-based cleaning, and real-time HTML/CSS content rewriting. However, Kataria emphasizes a critical shift in the nature of sanitization: it is no longer merely filtering or blocking tags; it is fundamentally about transformation. This transformation, involving structural mutations and repairs, introduces hidden execution paths that attackers can exploit. The underlying assumption that sanitizers eliminate XSS risk, or that a browser will interpret the output of a sanitizer in precisely the same secure way the sanitizer intended, is demonstrably false.

A key contributing factor to this disconnect is the differing parsing models between browsers and sanitizers. Browsers are designed for aggressive HTML rendering, prioritizing display even if the markup is malformed. They enter a "repair mode," recovering from errors and interpreting content to display it. In contrast, sanitizers are built to enforce strict security policies, blocking specific tags or events defined in configuration files. While a sanitizer processes user input and outputs a seemingly "safe" string, developers often concatenate this output into dynamic variables or templates, assuming its security. Kataria illustrates this with a basic example: an onmouseover event injected as an attribute. DOMPurify might not sanitize it because it contains no actual HTML tags. However, if this "sanitized" string is then directly concatenated into a div, it can trigger XSS, demonstrating that the developer's context of integration, not just the sanitizer's processing, is paramount. This highlights that developers often rely on sanitizers without fully understanding the context in which the sanitized output will be used, creating a significant gap for attackers to exploit.

Key Findings

▶ Watch: Understanding the browser vs. sanitizer parsing mismatch (2:40)

Kataria's research uncovers that sanitizers, rather than being infallible guardians, can actively contribute to the construction of XSS exploits. The central discovery is that the perceived security of sanitized output is often an illusion, stemming from a fundamental semantic drift between the Document Object Model (DOM) generated by the sanitizer and the DOM ultimately interpreted by the browser (or subsequent sanitizers) from the same "sanitized" string. This discrepancy arises from differing parsing rules, recovery mechanisms, and serialization behaviors.

The talk identifies several specific patterns that cause these sanitizer-induced XSS vulnerabilities:

  1. Namespace Confusion: HTML, SVG, and MathML have distinct namespaces, each with unique parsing rules. Attackers can exploit transitions between these namespaces to smuggle malicious content past sanitizers that might treat the content as inert text in one namespace but executable code in another. Most XSS attacks, the speaker notes, often arise from SVG and MathML due to this confusion.
  2. Broken Valid HTML Reconstruction: Sanitizers and browsers handle malformed or structurally unconventional HTML differently. For instance, HTML specifications do not allow nested forms. However, certain markup patterns can create a "trick" where a sanitizer might initially parse a nested form, but during serialization and subsequent re-parsing by a browser, the child form might be dropped or re-parented, leading to a modified DOM structure that was not intended.
  3. Token Merging / Character Collapsing: Attackers can split dangerous syntax (e.g., onerror) using HTML comments (on<!-- -->error) or other whitespace/newline characters. Sanitizers might remove these comments or normalize whitespace, thereby rejoining the split tokens into their malicious form. This is particularly effective in fragmented document parsing contexts, such as when content is assigned to element.innerHTML.
  4. CSS Normalization Induced XSS: Sanitizers attempting to clean CSS (like AntiSamy) can introduce vulnerabilities if they rely on flawed techniques, such as regex-based mutations instead of a robust Abstract Syntax Tree (AST)-based parsing and transformation. The @import rule in CSS is highlighted as a common vector for importing malicious styling that can bypass naive sanitization.
  5. DOM Relocation of Attribute Nodes & Serialization Side Effects: Differences in how parsers handle attributes, their values, and the process of converting a DOM back into a string (serialization) and then re-parsing that string back into a DOM can lead to attributes being relocated or reinterpreted in a way that enables XSS.

A critical finding is the increased risk in multi-stage HTML pipelines, where multiple sanitizers are chained together (e.g., a backend Java-based sanitizer like OWASP HTML Sanitizer, a CSS sanitizer like AntiSamy, and a frontend JavaScript sanitizer like DOMPurify or custom regexes). Each layer operates with its own grammar, rule sets, blocklists, or allowlists. A security property being preserved by Sanitizer A and Sanitizer B individually does not guarantee that the combined output of Sanitizer A followed by Sanitizer B will also be safe. These "compositional security problems" widen the exploitation gap, as attackers can craft payloads that exploit the subtle differences and policy inconsistencies between layers.

Technical Deep Dive

▶ Watch: Challenging assumption: Sanitizers can introduce XSS (4:10)

The modern sanitization pipeline, especially in complex applications like enterprise email platforms, involves a series of transformations. User input (HTML) first goes through an HTML parser or sanitizer, which constructs a DOM tree. Security policies (allow/deny tags and attributes) are applied to this DOM. If CSS is present, a dedicated CSS parser (e.g., AntiSamy) sanitizes it. After potential regex workarounds, a serializer converts the modified DOM back into a string. This string is then finally interpreted by the browser parser, which renders the content. Kataria stresses that each layer in this multi-layered stack often assumes the preceding layer has rendered the content safe, but when these layers diverge in their parsing and interpretation, attackers find exploitable gaps.

The core of the problem is demonstrated through DOM dissimilarity. The speaker illustrates this with the concept of nested forms. While the HTML specification explicitly disallows forms nested within other forms, certain markup can trick parsers. If an original HTML string form>div>form is parsed into a DOM, serialized back to a string, and then re-parsed by a browser, the resulting DOM might differ significantly. Specifically, the browser's aggressive repair mechanisms will typically drop the nested child form, leading to a simplified DOM with only one form. This difference between the original and re-serialized DOM, termed "semantic drift," is a root cause for many sanitizer-induced XSS attacks. Attackers leverage broken quotes, misnested tags, and other malformed structures to create this dissimilarity.

A prominent example of namespace confusion leading to XSS is the DOMPurify 2.2.0 vulnerability. The payload form><math><mtext> <form><mglyph><style>img src onerror alert 1 demonstrates how namespaces can be switched. The initial HTML form transitions to the MathML math namespace. The mtext tag, a MathML entry point, is then used to switch back to the HTML namespace, allowing an HTML form and mglyph tag to be injected. Critically, an HTML style tag, when in the HTML namespace, treats its content (img src onerror alert 1) as inert text. However, due to the nested form, when this payload is serialized and then re-parsed by the browser, the inner HTML form is dropped. This causes the style tag to incorrectly remain within the MathML namespace. In the MathML namespace, the style tag's content is not treated as inert text but can be interpreted as executable styling, leading to the img src onerror alert 1 payload triggering XSS. This vulnerability highlights how a sanitizer's initial interpretation, combined with the browser's re-parsing and repair of a structurally mutated output, can lead to unexpected execution. Subsequent XSS instances were found using table tags in a similar fashion, indicating a pattern.

Token merging and character collapsing exploits rely on splitting dangerous attributes or tags with HTML comments. For instance, img src="payload" on<!-- -->error="alert(1)" might pass through a sanitizer that removes comments, effectively rejoining on and error into a functional onerror attribute. This technique is particularly potent when the sanitized HTML is processed via fragmented document parsing, such as when assigned to element.innerHTML, which has different DOM reconstruction rules compared to full DOM parsing. Other mechanisms include newline and whitespace normalization, entity decoding, and null byte stripping, all of which can alter the intended structure of the payload.

For CSS normalization, Kataria strongly advises against regex-based mutations for security-critical transformations. Instead, he recommends parsing CSS into an Abstract Syntax Tree (AST), performing transformations on the AST, and then re-serializing. This provides a more robust and context-aware approach than string-based regex replacements. The @import CSS rule is noted as a common attack vector, allowing attackers to import malicious stylesheets, which many sanitizers attempt to block.

Demo / Proof of Concept

▶ Watch: Demonstration: Attribute context injection bypasses sanitizer (6:00)

The talk showcased three distinct case studies from real-world enterprise email platforms, acting as robust proofs of concept for sanitizer-induced XSS. These scenarios illustrate how security properties are lost during transformation, leading to exploitable vulnerabilities.

Case Study 1: Front-end Regex Bypass in an Enterprise Email Platform

This scenario involved a multi-stage pipeline: attacker-controlled HTML passed through two backend sanitizers, then subjected to a frontend regex-based sanitization before browser rendering. The initial payload, an anchor tag <a> with a style attribute containing an @import rule (e.g., <a style="rel:alt; style:@import url(javascript:alert(1))">...</a>), was deemed safe by the backend sanitizers. However, a frontend regex, intended to clean such constructs, was implemented incorrectly. The regex aimed to replace patterns like @import with an empty string or re-wrap them. The flaw occurred because the regex was not context-aware and incorrectly matched and replaced parts of the string, causing a premature closing of an attribute in the HTML. For example, if the regex matched style @import and replaced it, it could leave a dangling double-quote (") that prematurely closed an alt attribute (e.g., alt="), allowing a subsequent SVG onload payload (which was embedded in the original alt attribute) to "pop out" and be interpreted as an executable tag by the browser. The browser, in its attempt to repair the now malformed HTML, executed the SVG onload XSS.

Case Study 2: Front-end Inappropriate Regex Approach with Entity Decoding

In this case, an attacker payload with encoded entities (e.g., &#61; for = and &#39; for ') within an IMG alt attribute, containing an SVG onload payload (<img alt="<svg onload=alert(1)>" src="cid:..." />), was passed through backend sanitizers. The backend sanitizers correctly handled the encoded entities and kept the content safe. The problem arose when the frontend attempted to render this sanitized content within an iframe. During this process, the encoded entities were decoded back to their original characters. A subsequent frontend regex was designed to replace patterns like SRC=CID:. This regex, again lacking context awareness, incorrectly matched and replaced CID: within the alt attribute's decoded value. This replacement inadvertently closed the alt attribute prematurely, causing the SVG onload payload to become a separate, executable HTML element. The browser then repaired and executed the SVG, leading to XSS. This demonstrated a critical "security property lost in transformation": safe, encoded HTML became malformed and executable due to a sequence of decoding and context-unaware regex rewriting, followed by browser repair.

Case Study 3: AntiSamy Serialization Skip with Comment Stripping

This case involved a specific flaw in how a customer integrated the AntiSamy DOM scanner. AntiSamy, by design, lacked support for @media queries and, as a safety measure, would completely strip out HTML content if @media was detected. To support @media, the customer implemented a workaround: if the input HTML contained an @ symbol (indicating @media or @import), they would skip AntiSamy's serialization and directly append the raw, unsanitized HTML to the output stream. The attacker crafted a payload that used comment splitting around an @import rule (e.g., style @<-- -->import). AntiSamy would process the DOM and apply policies, but if the @import was detected (even with comments), the customer's logic would bypass the final serializer.serializeDOM() step. Consequently, the original, unsanitized HTML string (with the comment-split @import) was output. This raw HTML was then inserted into an iframe using innerHTML, triggering fragmented document parsing. In this parsing mode, the browser would rejoin the comments, activate the @import rule, and execute the malicious CSS, leading to XSS. This highlights the danger of custom workarounds that bypass core sanitizer functionalities and the different parsing behaviors in fragmented document contexts.

Defensive Implications

▶ Watch: Historical overview: Evolution of XSS prevention methods (8:00)

To effectively counter sanitizer-induced XSS, a paradigm shift in defensive strategies is required, moving beyond the simple assumption of blanket protection provided by sanitization libraries.

  1. Reject vs. Sanitize: The first and most robust defense is to reject user input if rich text formatting is not an absolute requirement. If rejection is not feasible (e.g., for rich text emails), then sanitization must be approached with extreme caution and rigor.
  2. Strict Parsing vs. Partial Rewriting: Avoid using regex-based string manipulation for security-critical content transformations. These methods are inherently prone to context-unaware errors and bypasses. Instead, for CSS, parse the content into an Abstract Syntax Tree (AST) and perform transformations on the AST, which ensures structural integrity and context awareness.
  3. Isolated Sandbox Rendering: For displaying untrusted or potentially malicious HTML content, always use sandboxed iframes. The sandbox attribute (e.g., <iframe sandbox="allow-scripts allow-forms">) can restrict JavaScript execution, form submissions, and other potentially dangerous actions, even if an XSS payload manages to slip through sanitization.
  4. Layered Validation with Browser-Consistent Parsing Model: When employing multi-stage sanitization pipelines, validate each layer independently and cumulatively. It's crucial to compare the DOM produced by each sanitizer with the final DOM that the browser will render. Any structural mutations, re-parenting of elements, or changes in attribute interpretation must be identified and understood. The goal is to ensure that the browser's final interpretation of the HTML is semantically identical to the intended secure output of the sanitization pipeline.
  5. Auditing Methodology for Sanitizer Side Effects: Implement a rigorous auditing process. Compare the DOM generated by each sanitizer against the final browser-rendered DOM. This involves looking for:
  • Changes in DOM structure post-sanitization.
  • Prematurely closed tags or reparented elements.
  • Differences in namespace handling (HTML, SVG, MathML).
  • The impact of fragmented document parsing versus full DOM parsing, as different rules apply.
  • Crucially, avoid any content rewriting or manipulation after the serialization phase, as this is where many vulnerabilities are introduced.
  1. Sanitizer-Induced Vulnerability Audit Checklist:
  • Multi-Sanitizer Pipeline Review: Are all sanitizers configured with the same, consistent security policies? Do they run sequentially, and is their canonicalization order audited?
  • Namespace Foreign Content Handling: Are SVG and MathML content explicitly allowed or disallowed? Are foreign content boundaries tested with misnested tags?
  • Structural Mutation Testing: Does malformed HTML change the DOM structure after sanitization?
  • Serialization and Rewriting: Is any rewriting occurring after serialization? Are prematurely closed tags or reparented elements being identified during DOM comparison?

By adopting these comprehensive defensive strategies, organizations can significantly reduce the risk of XSS vulnerabilities arising from the very sanitization processes intended to prevent them.

Key Takeaways

  • Sanitization as Transformation: Modern sanitization involves structural mutations and transformations, not just filtering. This process can inadvertently introduce new XSS attack surfaces by creating hidden execution paths.
  • Semantic Drift is Key: The fundamental cause of sanitizer-induced XSS is the semantic drift between the DOM generated by a sanitizer and the DOM ultimately interpreted by a browser from the "sanitized" output.
  • Multi-Stage Pipeline Risk: Chaining multiple sanitizers (backend, frontend, CSS-specific) significantly increases the attack surface due to differing parsing grammars, rule sets, and policy inconsistencies across layers.
  • Namespace and Structural Abuse: Attackers exploit namespace confusion (HTML, SVG, MathML) and structural mutations (e.g., nested forms, comment splitting, attribute relocation) to bypass sanitizers.
  • Avoid Regex for Security: Regex-based string manipulation for security transformations is often context-unaware and prone to bypasses. Prefer AST-based parsing and transformation for robust content sanitization, especially for CSS.
  • Thorough DOM Auditing is Essential: Effective defense requires comparing the DOM at each stage of sanitization and the final browser-rendered DOM to identify structural mutations and ensure browser-consistent parsing, particularly considering fragmented document parsing.

About the Speaker(s)

Ashish Kataria is a Security Architect Engineer at Synopsys, where he focuses on securing complex systems and applications. Prior to his role at Synopsys, Ashish served as a Scientist at the National Informatics Center, a premier organization under the Indian Ministry of Electronics and Information Technology. His extensive experience in both government and corporate sectors has provided him with deep insights into web security, particularly in understanding and mitigating pervasive vulnerabilities like Cross-Site Scripting. Kataria's research highlights practical, real-world challenges in application security, offering valuable perspectives on evolving threat landscapes and defensive strategies.

Reviews

Dr. Zero (Offensive Security Researcher) — STRONG ACCEPT

Kataria does something genuinely useful: he flips the sanitizer-as-solution narrative on its head and shows, with real CVEs and three enterprise case studies, that sanitizers can be the exploit primitive rather than the guard. The compositional security failure angle — specifically that chaining sanitizers creates emergent attack surfaces from parser disagreements — is well-argued and practically grounded.

Heather Calloway (CISO) — SOLID

Kataria identifies a genuine and underappreciated problem — sanitization pipelines as XSS generators, not just XSS mitigators — and backs it with three real-world enterprise case studies. The technical work is credible and the defensive checklist is concrete, but this talk stays firmly in the AppSec practitioner lane and never climbs to the organizational or governance level where the decisions that enable these vulnerabilities actually get made.

→ Top-rated talks at Nullcon Goa 2026

All talks from Nullcon Goa 2026