Sep 25, 2026·7 min read·18 visits
The xhtml-purifier library does not encode double quotes in attribute values during re-serialization, allowing attackers to inject malicious HTML attributes like event handlers and execute arbitrary JavaScript.
A critical sanitizer bypass vulnerability exists in the xhtml-purifier Node.js library prior to version 0.4.3. Due to a lack of HTML entity encoding during the attribute re-serialization phase, unauthenticated remote attackers can break out of double-quoted attribute contexts to inject arbitrary script handlers, resulting in Cross-Site Scripting.
The Node.js library xhtml-purifier (developed by cstigler) is designed to take raw, untrusted HTML input and sanitize it into compliant, safe XHTML or HTML output. This library is commonly integrated into web applications to allow safe user-generated content, such as blog comments, forum posts, or formatted text. The library utilizes an internal parsing mechanism to analyze elements and ensure only pre-approved tags and attributes exist in the output.
However, in versions prior to 0.4.3, xhtml-purifier fails to perform appropriate encoding on attribute values during its final serialization phase. Although the parser successfully limits elements to whitelisted attributes, it does not sanitize the contents of those attributes against context-breaking characters. This allows attackers to supply custom payloads inside permitted attributes to modify the structural syntax of the output document.
The resulting vulnerability is classified under CWE-79 (Improper Neutralization of Input During Web Page Generation) and CWE-116 (Improper Encoding or Escaping of Output). Because the injection happens during serialization after the parsing and validation phases have concluded, the injected characters bypass the sanitization filters entirely. This leads to a reliable stored or reflected cross-site scripting (XSS) vulnerability depending on how the application processes and displays the output.
The core vulnerability lies within the re-serialization phase of xhtml-purifier, specifically inside the attributeString() function located in XHTMLPurifier.js. When the library processes HTML, it converts the raw input into an in-memory tree representation. During this tree construction, the parser identifies whitelisted attributes, such as class, style, or title, and captures their corresponding values as literal string data without validation of special formatting characters.
During the serialization stage, the library recreates the sanitized HTML markup by iterating over the attributes and reconstructing the tags. The function outputs these values by concatenating the raw attribute value straight into double-quoted structures: string += " " + name + "=\"" + value + "\"";. Since the library does not search for, escape, or entity-encode the double-quote (") character inside the value variable, any double-quote within a permitted attribute will successfully terminate the attribute scope in the output string.
Consequently, an attacker who injects a double-quote into an allowed attribute value can append arbitrary characters that will be interpreted as new attributes by a browser. Because the input parser already validated the parent attribute as safe, the injected content bypasses the tag-stripping logic. The downstream browser parser processes the unescaped double-quote, terminates the whitelisted attribute, and interprets the malicious payload as valid, active attributes on the same tag.
The vulnerability is highlighted when analyzing the code before the patch in XHTMLPurifier.js around line 148. The original serialization loop concatenates raw values directly without filtering:
// Vulnerable Code Path in XHTMLPurifier.js
for (var name in attributes) {
var value = attributes[name];
// ... validation logic
string += " " + name + "=\"" + value + "\"";
}To resolve this issue, the developer modified the serialization logic in commit 21d461ad23e7bc9b3073693d5b51b9b8662044d3 to implement robust escaping. The following code fragment shows the introduced changes:
// Patched Code Path in XHTMLPurifier.js
var encodedValue = String(value)
.replace(/&(?![a-zA-Z][a-zA-Z0-9]*;|#\d+;|#x[0-9a-fA-F]+;)/g, "&")
.replace(/"/g, """)
.replace(/</g, "<")
.replace(/>/g, ">");
string += " " + name + "=\"" + encodedValue + "\"";This remediation ensures that any instance of a double-quote character is transformed into its corresponding safe HTML entity ("). Additionally, the patch includes escaping for less-than (<) and greater-than (>) signs to prevent premature element closure. The regular expression for ampersands uses a negative lookahead to avoid re-encoding already valid, well-formed HTML entities, preserving application behavior while protecting against bypass vectors.
Exploitation of CVE-2026-61784 requires the target application to utilize a vulnerable version of xhtml-purifier to sanitize untrusted user input and subsequently render the output to users. The attacker must target a whitelisted HTML element and attribute to prevent the initial parser from dropping the entire node. Attributes such as class, title, or style are suitable candidates for this vector.
The attacker crafts a payload that embeds double quotes inside a single-quoted HTML tag. When processed by xhtml-purifier, the parser accepts the overall element and parses the inner content as the value of the whitelisted attribute. An example payload format is structured as follows:
<span class='test" onmouseover="javascript:alert(document.cookie)' style='color:red;'>Hover here</span>When the serialization logic executes, the resulting HTML string emitted by the library is structured as:
<span class="test" onmouseover="javascript:alert(document.cookie)" style="color:red;">Hover here</span>When this output is loaded by the victim's browser, the parser recognizes onmouseover as a valid event handler attribute of the span element. Once a victim interacts with the element, the javascript payload is executed in the context of the vulnerable origin. This allows the attacker to execute arbitrary script, steal session cookies, or manipulate the page structure.
The impact of CVE-2026-61784 is assessed with a CVSS v3.1 base score of 6.1 (Medium). The attack vector is Network, meaning exploitation can occur remotely without local access requirements. The attack complexity is Low, as the payload relies on basic HTML structures and requires no specialized configuration or timing. No privileges are required to exploit the flaw, but User Interaction is required for the payload to be rendered and triggered in a browser context.
The potential impact on confidentiality is Low, as the executing script can read sensitive DOM data, session tokens, or other client-side information. Similarly, the impact on integrity is Low because the injected code can execute requests or modify application state on behalf of the victim. There is no direct impact on availability.
While categorized as Medium, the impact scales significantly if the application handles privileged administrative sessions. A successful cross-site scripting attack against an administrative user could lead to complete administrative takeover of the backend platform, illustrating how client-side bypasses can act as primary entry points for more severe downstream compromises.
The primary remediation path is upgrading the xhtml-purifier dependency to version 0.4.3 or later. This version contains the updated serialization engine that correctly entity-encodes attribute values. Organizations utilizing automated package managers should update their definitions to exclude vulnerable versions.
To detect potential exploitation attempts at the network or application layer, security teams can employ custom rules. Web Application Firewalls (WAF) can be configured to detect attribute breakout attempts within JSON or form inputs that contain HTML. For example, patterns looking for double quotes followed immediately by event handlers inside single-quoted elements can identify active payloads.
# Example detection pattern concept for WAF or input filtering
(?i)<\w+\s+[^>]*\s*=\s*['"][^'"]*["'][^>]*\s+on[a-z]+=
Organizations should also conduct automated dependency audits using tools like npm audit or static application security testing (SAST) to discover instances of the library across all active codebases. If immediate upgrading is impossible, a temporary workaround involves manually stripping or sanitizing double quotes from input strings before passing them to the purifier library.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
xhtml-purifier cstigler | < 0.4.3 | 0.4.3 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 |
| Attack Vector | Network |
| CVSS Score | 6.1 (Medium) |
| EPSS Score | 0.00168 |
| Impact | Sanitizer Bypass / Cross-Site Scripting (XSS) |
| Exploit Status | PoC / Functional Tests available |
| CISA KEV Status | Not Listed |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
CVE-2026-16454 is an object-level authorization bypass vulnerability (CWE-284, CWE-862) in Eclipse hawkBit versions 1.0.3 and prior. The flaw exists within the Direct Device Integration (DDI) REST controller (hawkbit-ddi-resource), where endpoints responsible for enumerating software module metadata and serving firmware binaries fail to verify whether the requested software module is assigned to the authenticated device. Consequently, any device with valid credentials (such as a TargetToken or GatewayToken) can enumerate software module identifiers and download arbitrary firmware artifacts across the entire tenant namespace.
CVE-2026-62284 (GHSA-5w5g-j6hw-6p8f) is a code injection and server-side request forgery vulnerability in the console-proxy component of the OSAC Operator. The RemoteConfigResolver parses Kubernetes Secrets containing kubeconfig files via clientcmd.RESTConfigFromKubeConfig without sanitizing execution-related fields. An attacker with RBAC permissions to create or modify labeled Secrets in monitored namespaces can supply a malicious exec credential plugin, resulting in arbitrary command execution within the console-proxy pod.
CVE-2026-62361 (GHSA-xgjr-7j9q-2h4r) is an authenticated SQL injection and authorization bypass vulnerability in listmonk, an open-source, self-hosted newsletter and mailing list manager written in Go. In versions prior to 6.2.0, the subscriber export endpoint (GET /api/subscribers/export) directly interpolates user-supplied SQL filter expressions into a PostgreSQL query without invoking the table allowlist validation function (validateQueryTables). Consequently, authenticated users possessing the subscribers:sql_query and subscribers:get_all permissions can bypass relational access controls, execute arbitrary subqueries against restricted tables such as users and settings, and modify database state via writable Common Table Expressions (CTEs).
CVE-2026-28385 (GHSA-3gq2-x4qg-p4g6) is a Server-Side Request Forgery (SSRF) vulnerability in Canonical LXD versions 4.12 through 6.9. An authenticated user possessing the can_create_images entitlement can force the LXD daemon to execute arbitrary outbound HTTP and HTTPS requests via the /1.0/images API endpoint. Due to the absence of egress destination validation, an attacker can probe host loopback services, RFC 1918 private network segments, and cloud Instance Metadata Services (IMDS) from the network position of the privileged LXD daemon.
Canonical LXD and LXC Incus contain an arbitrary file write vulnerability (CWE-73 / CWE-59) in the `/1.0/instances/<name>/exec` REST API endpoint. When an instance is unpacked from an image archive, top-level symbolic links are extracted directly onto the host filesystem within the instance storage directory. If a crafted image includes a symbolic link named `exec-output` pointing to an arbitrary host path, invoking the execution endpoint with `record-output: true` causes the privileged host daemon to follow the symlink and write command output files directly to the target host directory. An authenticated attacker with permissions to import images and execute commands can exploit this flaw to write controlled content to sensitive host directories such as `/etc/cron.d`, resulting in arbitrary code execution on the host as `root`.
CVE-2026-48749 (tracked as GHSA-vghh-5rfx-xhq8 for LXD and GHSA-2q3f-q5pq-g8wv for Incus) is a critical container escape vulnerability in the Canonical LXD and Linux Containers Incus system container managers. By importing a specially crafted container image archive containing duplicate tar member headers, an authenticated attacker can replace the instance rootfs directory with a symbolic link pointing to the underlying host root filesystem. When performing file operations on a stopped container, the privileged forkfile helper binary resolves the symbolic link without confinement and chroots directly into the host filesystem, granting arbitrary root-level file read and write access.