Severity by source
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Primary rating from Vendor (https://github.com/xmldom/xmldom).
CVSS VectorVendor: https://github.com/xmldom/xmldom
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Lifecycle Timeline
8Blast Radius
ecosystem impact- 4 npm packages depend on @xmldom/xmldom (4 direct, 0 indirect)
- 1,984 npm packages depend on xmldom (850 direct, 1,160 indirect)
Ecosystem-wide dependent count for version 0.9.0 and other introduced versions.
DescriptionCVE.org
Summary
The package allows attacker-controlled comment content to be serialized into XML without validating or neutralizing comment breaking sequences. As a result, an attacker can terminate the comment early and inject arbitrary XML nodes into the serialized output.
---
Details
The issue is in the DOM construction and serialization flow for comment nodes.
When createComment(data) is called, the supplied string is stored as comment data through the generic character-data handling path. That content is kept as-is. Later, when the document is serialized, the serializer writes comment nodes by concatenating the XML comment delimiters with the stored node.data value directly.
That behavior is unsafe because XML comments are a syntax-sensitive context. If attacker-controlled input contains a sequence that closes the comment, the serializer does not preserve it as literal comment text. Instead, it emits output where the remainder of the payload is treated as live XML markup.
This is a real injection bug, not a formatting issue. The serializer already applies context-aware handling in other places, such as escaping text nodes and rewriting unsafe CDATA terminators. Comment content does not receive equivalent treatment. Because of that gap, untrusted data can break out of the comment boundary and modify the structure of the final XML document.
---
PoC
const { DOMImplementation, DOMParser, XMLSerializer } = require('@xmldom/xmldom');
const doc = new DOMImplementation().createDocument(null, 'root', null);
doc.documentElement.appendChild(
doc.createComment('--><injected attr="1"/><!--')
);
const xml = new XMLSerializer().serializeToString(doc);
console.log(xml);
// <root><!----><injected attr="1"/><!----></root>
const reparsed = new DOMParser().parseFromString(xml, 'text/xml');
console.log(reparsed.documentElement.childNodes.item(1).nodeName);
// injected---
Impact
An application that uses the package to build XML from untrusted input can be made to emit attacker-controlled elements outside the intended comment boundary. That allows the attacker to alter the meaning and structure of generated XML documents.
In practice, this can affect any workflow that generates XML and then stores it, forwards it, signs it, or hands it to another parser. Realistic targets include XML-based configuration, policy documents, and message formats where downstream consumers trust the serialized structure.
---
Disclosure
This vulnerability was publicly disclosed at 2026-04-06T11:25:07Z via xmldom/xmldom#987, which was subsequently closed without being merged.
---
Fix Applied
> ⚠ Opt-in required. Protection is not automatic. Existing serialization calls remain > vulnerable unless { requireWellFormed: true } is explicitly passed. Applications that pass > untrusted data to createComment() or mutate comment nodes with untrusted input (via > appendData, insertData, replaceData, .data =, or .textContent =) should audit all > serializeToString() call sites and add the option.
XMLSerializer.serializeToString() now accepts an options object as a second argument. When { requireWellFormed: true } is passed, the serializer throws InvalidStateError before emitting a Comment node whose .data would produce malformed XML.
On @xmldom/xmldom ≥ 0.9.10, the full W3C DOM Parsing §3.2.1.4 check is applied: throws if .data contains -- anywhere, ends with -, or contains characters outside the XML Char production.
On @xmldom/xmldom ≥ 0.8.13 (LTS), only the --> injection sequence is checked. The 0.8.x SAX parser accepts comments containing -- (without >), so throwing on bare -- would break a previously-working round-trip on that branch. The --> check is sufficient to prevent injection.
PoC - fixed path
const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom');
const doc = new DOMImplementation().createDocument(null, 'root', null);
doc.documentElement.appendChild(doc.createComment('--><injected attr="1"/><!--'));
// Default (unchanged): verbatim - injection present
const unsafe = new XMLSerializer().serializeToString(doc);
console.log(unsafe);
// <root><!----><injected attr="1"/><!----></root>
// Opt-in guard: throws InvalidStateError before serializing
try {
new XMLSerializer().serializeToString(doc, { requireWellFormed: true });
} catch (e) {
console.log(e.name, e.message);
// InvalidStateError: The comment node data contains "--" or ends with "-" (0.9.x)
// InvalidStateError: The comment node data contains "-->" (0.8.x - only --> is checked)
}Why the default stays verbatim
The W3C DOM Parsing and Serialization spec §3.2.1.4 defines a require well-formed flag whose default value is false. With the flag unset, the spec explicitly permits serializing ill-formed comment content verbatim - this is also the behavior of browser implementations (Chrome, Firefox, Safari): new XMLSerializer().serializeToString(doc) produces the injection sequence without error in all major browsers.
Unconditionally throwing would be a behavioral breaking change with no spec justification. The opt-in requireWellFormed: true flag allows applications that require injection safety to enable strict mode without breaking existing deployments.
Residual limitation
The fix operates at serialization time only. There is no creation-time check in createComment - the spec does not require one for comment data. Any path that leads to a Comment node with -- in its data (createComment, appendData, .data =, etc.) produces a node that serializes safely only when { requireWellFormed: true } is passed to serializeToString.
AnalysisAI
XML node injection in the @xmldom/xmldom npm package allows remote attackers to inject arbitrary XML elements via maliciously crafted comment content containing the sequence '-->' which prematurely terminates comments during serialization. Applications processing untrusted input through createComment() or manipulating comment node data can emit structurally altered XML that downstream consumers parse as attacker-controlled elements. Public exploit code exists (GitHub PR #987). CVSS:4.0 rates this 8.7 (High) with network vector, low complexity, and no privileges required. Vendor-released patches require opt-in protection flag { requireWellFormed: true } to maintain backward compatibility with W3C spec defaults; existing code remains vulnerable unless explicitly migrated.
Technical ContextAI
The vulnerability resides in the XML serialization implementation of the @xmldom/xmldom JavaScript library, specifically in the XMLSerializer class that converts DOM trees to XML text. The affected packages (pkg:npm/@xmldom_xmldom and legacy pkg:npm/xmldom) implement W3C DOM Parsing and Serialization standards for Node.js environments. CWE-91 (XML Injection) occurs because the serializer concatenates comment node data directly between XML comment delimiters (<!-- and -->) without neutralizing comment-terminating sequences. While the serializer correctly escapes text nodes and rewrites unsafe CDATA terminators, comment nodes receive no equivalent context-sensitive encoding. When attacker-controlled data containing '-->' reaches the serialization path via createComment(), appendData(), insertData(), replaceData(), or direct assignment to .data or .textContent properties, the serializer emits syntactically valid but structurally compromised XML where content after the injected terminator is parsed as live markup rather than comment text. This class of injection affects any XML-processing workflow where document structure carries semantic weight-configuration files, SAML assertions, signed documents, policy engines, or message formats consumed by downstream XML parsers.
RemediationAI
Upgrade to @xmldom/xmldom version 0.8.13 (for 0.8.x LTS users) or 0.9.10 (for 0.9.x users) as documented in release notes at https://github.com/xmldom/xmldom/releases/tag/0.8.13 and https://github.com/xmldom/xmldom/releases/tag/0.9.10. CRITICAL STEP: Audit all serializeToString() call sites in application code and pass { requireWellFormed: true } as the second argument-protection is not automatic and default behavior remains vulnerable for backward compatibility with W3C DOM Parsing spec section 3.2.1.4. Example: new XMLSerializer().serializeToString(doc, { requireWellFormed: true }). This triggers InvalidStateError before emitting malformed comments, preventing injection. On 0.9.x the check enforces full W3C constraints (throws on any '--' substring, trailing '-', or non-XML-Char characters). On 0.8.x LTS the check is narrowed to only the injection sequence '-->' to preserve round-trip compatibility with existing 0.8.x parser behavior that accepts bare '--' in comments. SIDE EFFECT: Enabling requireWellFormed will cause runtime exceptions if existing code legitimately creates comments containing '--' sequences-applications must handle InvalidStateError or sanitize comment content before creation. For users of the deprecated xmldom package (no fix available): migrate to @xmldom/xmldom 0.8.13+ or implement application-layer sanitization by replacing /--/g with '--' before calling createComment() or mutating comment.data. If migration is blocked, enforce least-privilege input validation: reject or escape comment content from untrusted sources, or switch to text nodes with proper escaping. Related commits: https://github.com/xmldom/xmldom/commit/b397540889086da868c30c366ad5c220d1a750c7 and https://github.com/xmldom/xmldom/commit/fda7cc313de30243fea35cada64e0bb12099c2a1.
The PDF reader in Mozilla Firefox before 39.0.3, Firefox ESR 38.x before 38.1.1, and Firefox OS before 2.2 allows remote
Mozilla Firefox before 22.0, Firefox ESR 17.x before 17.0.7, Thunderbird before 17.0.7, and Thunderbird ESR 17.x before
Mozilla Firefox before 18.0, Firefox ESR 10.x before 10.0.12 and 17.x before 17.0.2, Thunderbird before 17.0.2, Thunderb
Use-after-free vulnerability in the serializeToStream implementation in the XMLSerializer component in Mozilla Firefox b
The Chrome Object Wrapper (COW) implementation in Mozilla Firefox before 16.0, Firefox ESR 10.x before 10.0.8, Thunderbi
The crypto.generateCRMFRequest function in Mozilla Firefox before 23.0, Firefox ESR 17.x before 17.0.8, Thunderbird befo
An issue was discovered in the Cisco WebEx Extension before 1.0.7 on Google Chrome, the ActiveTouch General Plugin Conta
The XrayWrapper implementation in Mozilla Firefox before 35.0 and SeaMonkey before 2.32 does not properly interact with
The Chrome Object Wrapper (COW) implementation in Mozilla Firefox before 18.0, Firefox ESR 17.x before 17.0.2, Thunderbi
The Web IDL implementation in Mozilla Firefox before 28.0, Firefox ESR 24.x before 24.4, Thunderbird before 24.4, and Se
Mozilla Firefox before 28.0, Firefox ESR 24.x before 24.4, Thunderbird before 24.4, and SeaMonkey before 2.25 allow remo
The Firefox sandbox in Adobe Flash Player before 10.3.183.67 and 11.x before 11.6.602.171 on Windows and Mac OS X, and b
Same weakness CWE-91 – XML Injection (aka Blind XPath Injection)
View allSame technique Information Disclosure
View allVendor StatusVendor
SUSE
Severity: High| Product | Status |
|---|---|
| SUSE Linux Enterprise Desktop 15 SP7 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP7 | Fixed |
| SUSE Linux Enterprise Module for Python 3 15 SP7 | Fixed |
| SUSE Linux Enterprise Server 15 SP7 | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP7 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP4 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP4-LTSS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP5 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP5-LTSS | Fixed |
| SUSE Linux Enterprise Module for Python 3 15 SP6 | Fixed |
| SUSE Linux Enterprise Module for Server Applications 15 SP4 | Fixed |
| SUSE Linux Enterprise Module for Server Applications 15 SP5 | Fixed |
| SUSE Linux Enterprise Server 15 SP4 | Fixed |
| SUSE Linux Enterprise Server 15 SP4-LTSS | Fixed |
| SUSE Linux Enterprise Server 15 SP5 | Fixed |
| SUSE Linux Enterprise Server 15 SP5-LTSS | Fixed |
| SUSE Linux Enterprise Server 15 SP6 | Fixed |
| SUSE Linux Enterprise Server 15 SP6-LTSS | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP6 | Fixed |
| SUSE Manager Proxy 4.3 | Fixed |
| SUSE Manager Proxy LTS 4.3 | Fixed |
| SUSE Manager Retail Branch Server 4.3 | Fixed |
| SUSE Manager Retail Branch Server LTS 4.3 | Fixed |
| SUSE Manager Server 4.3 | Fixed |
| SUSE Manager Server LTS 4.3 | Fixed |
| SUSE CaaS Platform 4.0 | Fixed |
| SUSE Enterprise Storage 6 | Fixed |
| SUSE Enterprise Storage 7 | Fixed |
| SUSE Enterprise Storage 7.1 | Fixed |
| SUSE Linux Enterprise Desktop 15 SP6 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP1 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP1-ESPOS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP1-LTSS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP2 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP2-ESPOS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP2-LTSS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP3 | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP3-ESPOS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP3-LTSS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP4-ESPOS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP5-ESPOS | Fixed |
| SUSE Linux Enterprise High Performance Computing 15 SP6 | Fixed |
| SUSE Linux Enterprise Module for Server Applications 15 SP1 | Fixed |
| SUSE Linux Enterprise Module for Server Applications 15 SP2 | Fixed |
| SUSE Linux Enterprise Module for Server Applications 15 SP3 | Fixed |
| SUSE Linux Enterprise Real Time 15 SP2 | Fixed |
| SUSE Linux Enterprise Real Time 15 SP3 | Fixed |
| SUSE Linux Enterprise Real Time 15 SP4 | Fixed |
| SUSE Linux Enterprise Server 15 SP1 | Fixed |
| SUSE Linux Enterprise Server 15 SP1-BCL | Fixed |
| SUSE Linux Enterprise Server 15 SP1-LTSS | Fixed |
| SUSE Linux Enterprise Server 15 SP2 | Fixed |
| SUSE Linux Enterprise Server 15 SP2-BCL | Fixed |
| SUSE Linux Enterprise Server 15 SP2-LTSS | Fixed |
| SUSE Linux Enterprise Server 15 SP3 | Fixed |
| SUSE Linux Enterprise Server 15 SP3-BCL | Fixed |
| SUSE Linux Enterprise Server 15 SP3-LTSS | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP1 | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP2 | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP3 | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP4 | Fixed |
| SUSE Linux Enterprise Server for SAP Applications 15 SP5 | Fixed |
| SUSE Manager Proxy 4.0 | Fixed |
| SUSE Manager Proxy 4.1 | Fixed |
| SUSE Manager Proxy 4.2 | Fixed |
| SUSE Manager Retail Branch Server 4.0 | Fixed |
| SUSE Manager Retail Branch Server 4.1 | Fixed |
| SUSE Manager Retail Branch Server 4.2 | Fixed |
| SUSE Manager Server 4.0 | Fixed |
| SUSE Manager Server 4.1 | Fixed |
| SUSE Manager Server 4.2 | Fixed |
| openSUSE Leap 15.3 | Fixed |
| openSUSE Leap 15.4 | Fixed |
| openSUSE Leap 15.5 | Fixed |
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-28285
GHSA-j759-j44w-7fr8