CVE-2026-83618
highEPSS 0.006 · 46 %ileDERUUSEPSS · scored 2026-10-18
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.10 until 0.9.12, the requireWellFormed: true serializer validates DocumentType.publicId and DocumentType.systemId with PubidLiteral_match and SystemLiteral_match expressions produced by reg() in lib/grammar.js, which inherit the multiline flag. A complete valid literal on the first line can therefore satisfy the matcher while U+000A, U+000D, U+2028, or U+2029 and breakout markup remain in the emitted <!DOCTYPE ...> declaration. This bypasses the strict-serialization mitigation for the earlier DocumentType injection advisory; creation and direct property assignment remain unvalidated by design. This issue is fixed in @xmldom/xmldom version 0.9.12.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · medium–high · 6.6–8.7
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (7)
Products and version ranges known to be affected.
- IBM WebSphere Service Registry and Repositoryall versionscert_bundDEcpe:/a:ibm:websphere_service_registry_and_repository:-
advisories (2)
Vendor and ecosystem advisories describing this.
- WID-SEC-W-2026-3596IBM App Connect Enterprise: Mehrere SchwachstellenDeutsch2026-09-27csaf · cert_bundDE
Ein Angreifer kann mehrere Schwachstellen in IBM App Connect Enterprise ausnutzen, um Sicherheitsvorkehrungen zu umgehen, um einen Denial of Service Angriff durchzuführen, um Informationen offenzulegen, um Dateien zu manipulieren und um einen Cross-Site Scripting Angriff durchzuführen.
- GHSA-vr34-hp96-76ppxmldom: requireWellFormed DocType publicId/systemId validation is bypassable via an embedded line terminator2026-09-08ghsa · osvUS
## Summary An embedded line terminator bypasses the `requireWellFormed` serializer check for a `DocumentType`'s publicId and systemId. The check was added to fix GHSA-f6ww-3ggp-fr8h; an id whose first line is a valid literal slips past it and is emitted verbatim into the `<!DOCTYPE …>` declaration, so the markup after the line terminator breaks out into the surrounding document. Callers who enabled `requireWellFormed` to neutralize DocumentType injection remain exposed. ## Details `publicId` and `systemId` are stored as raw values **including their surrounding quotes**, and the `PubidLiteral`/`SystemLiteral` productions include those quotes. The serializer validates them with `g.PubidLiteral_match.test(publicId)` and `g.SystemLiteral_match.test(systemId)`, where both matchers are `reg('^', …, '$')` and inherit the `m` flag from xmldom's shared regexp builder. Under `m`, `$` matches at an interior line terminator, so a value such as `"valid pubid"\n"><!ENTITY …>` satisfies the matcher on its first line (`"valid pubid"` is a complete `PubidLiteral`) and the whole value — including the post-newline breakout — is emitted after `PUBLIC`/`SYSTEM`. ### Root Cause 1. A shared regexp builder compiles anchored productions with the `m` flag. 2. `^…$` under `m` are line anchors, not string anchors. 3. A full-string validator built on such a production (`.test()`) accepts any string with one conforming line, so a complete, valid literal on the first line passes even though a line terminator and breakout markup follow. `PubidChar` excluding `<`/`>` does not prevent it — the breakout is appended *after* the literal, not embedded inside it. The triggering line terminators are the ECMAScript `LineTerminator` set: U+000A, U+000D, U+2028, U+2029. ## Affected Versions Only `@xmldom/xmldom` 0.9.x is affected. The vulnerable matchers are built by `lib/grammar.js`'s `m`-flagged `reg()` builder, and the DocType `publicId`/`systemId` `requireWellFormed` check that consumes them was introduced in 0.9.10 (the GHSA-f6ww-3ggp-fr8h fix); 0.9.10 and 0.9.11 carry it. `0.8.x` performs the same `requireWellFormed` check with inline, non-`m` regular expressions and is not affected. The unscoped `xmldom` package has no `grammar.js` and no `requireWellFormed` serializer, so there is no check to bypass. ## Proof of Concept ```js const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom'); const impl = new DOMImplementation(); // publicId: complete literal on line 1, then newline + breakout const dt = impl.createDocumentType('html', '"valid pubid"\n"><!ENTITY xxe SYSTEM "file:///etc/passwd">', ''); const doc = impl.createDocument(null, 'root', dt); console.log(new XMLSerializer().serializeToString(doc, { requireWellFormed: true })); // Observed (no throw): // <!DOCTYPE html PUBLIC "valid pubid" // "><!ENTITY xxe SYSTEM "file:///etc/passwd">><root/> // Expected: InvalidStateError (publicId is not a valid PubidLiteral). // Control: a single-line invalid publicId ("no-surrounding-quotes<>") DOES throw InvalidStateError, // confirming the check is active and specifically bypassed by the line terminator. ``` ## Impact - **Bypass of the GHSA-f6ww-3ggp-fr8h mitigation.** Applications that adopted `requireWellFormed: true` to neutralize DocumentType injection remain exposed. - **XML structure injection into the DOCTYPE**, including injected markup / entity declarations after the public or system identifier. ## Fix Applied The anchored `PubidLiteral`/`SystemLiteral` validators used by the `requireWellFormed` serializer no longer treat an interior line terminator as satisfying the `$` anchor, so a `publicId` or `systemId` containing any ECMAScript `LineTerminator` (U+000A, U+000D, U+2028, U+2029) is rejected with `InvalidStateError`. Valid single-line identifiers serialize unchanged, and the default serialization path is unaffected. > **⚠ Opt-in required.** Protection is not automatic. Existing serialization calls remain vulnerable > unless `{ requireWellFormed: true }` is explicitly passed. Applications that serialize untrusted DOM > content should audit all `serializeToString()` call sites and add it. ### Proof of Concept - fixed path ```js const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom'); const impl = new DOMImplementation(); const dt = impl.createDocumentType('html', '"valid pubid"\n"><!ENTITY xxe SYSTEM "file:///etc/passwd">', ''); const doc = impl.createDocument(null, 'root', dt); // Default path (requireWellFormed off) — unchanged, still emits verbatim: console.log(new XMLSerializer().serializeToString(doc)); // <!DOCTYPE html PUBLIC "valid pubid" // "><!ENTITY xxe SYSTEM "file:///etc/passwd">><root/> // Opt-in path — now throws instead of emitting the breakout: new XMLSerializer().serializeToString(doc, { requireWellFormed: true }); // InvalidStateError: DocumentType publicId is not a valid PubidLiteral ``` ### Why the default stays verbatim The W3C DOM Parsing "require well-formed" flag defaults to false, and a browser `XMLSerializer` emits the DOCTYPE verbatim. Unconditionally throwing on a malformed `publicId`/`systemId` would be an unjustified breaking change to the default path, so the fix tightens only the opt-in `requireWellFormed` validator, matching browser and spec defaults. ### Residual limitation The guarantee holds only for callers that pass `{ requireWellFormed: true }`; the default serialization path still emits `publicId`/`systemId` verbatim. `publicId` and `systemId` are not validated at creation (`createDocumentType`) or on direct property assignment (`documentType.publicId = …`) — the WHATWG DOM specification places no well-formedness constraint on these fields at creation time, so the serializer is the spec-aligned enforcement point.
also known as (1)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (4) nvd
External citations — patches, advisories, analysis.
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan