CVE-2026-83612
xmldom: HTML raw-text closing-tag case mismatch causes output amplification
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.7
xmldom: HTML raw-text closing-tag case mismatch causes output amplification
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
- Record
CVE-2026-83612- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-178, CWE-400
- Updated
- 2026-11-02
EUVDEUVD-2026-69227
8.7
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
- Record
EUVD-2026-69227- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-6mj3-qw4j-hgrw
8.7
xmldom: HTML raw-text closing-tag case mismatch causes output amplification
Summary
In HTML mode (text/html), a raw-text element (script, style, textarea, title) whose closing
tag differs in case from its opening tag (e.g. </ScRiPt> for <script>) is mishandled by the
parser, producing quadratic (O(n²)) output growth — a small crafted document parses and serializes
into output orders of magnitude larger, exhausting CPU and memory. A modest input of tens of KB can
therefore cause a denial of service in any service that parses untrusted HTML with xmldom. Only HTML
mode is affected.
Details
The parser calls parseHtmlSpecialContent for each raw-text element in HTML mode, matched via
isHTMLRawTextElement / isHTMLEscapableRawTextElement (so all four types — script, style,
textarea, title — are in scope). It searches for the element's closing tag with
source.indexOf('</' + tagName + '>', elStartEnd), a byte-for-byte case-sensitive match. A
mixed-case closing tag never matches, so the search returns -1, and the following
source.substring(elStartEnd + 1, -1) extracts text backwards from the start of the document
instead of the element's content. The function then returns -1 to the parse loop, which cannot
advance normally and falls back to character-by-character reprocessing. Every raw-text element
re-captures all source text preceding it, so output grows as O(n²) in the number of such elements.
Root Cause
- Case-sensitive close-tag search (
lib/sax.js:549):source.indexOf('</' + tagName + '>', elStartEnd)does not fold case, contrary to the WHATWG HTML RAWTEXT end-tag-name rule. - Unguarded
-1(lib/sax.js:550):source.substring(elStartEnd + 1, elEndStart)runs even whenelEndStart === -1, extracting text backwards from position 0. - Unstable progression (
lib/sax.js:556): the function returnselEndStart(-1), driving repeated character-by-character fallback in the parse loop.
Affected Versions
Only the 0.9.x line is affected — the amplification was introduced in 0.9.0-beta.1 when
parseHtmlSpecialContent was refactored, and remains through 0.9.11. The 0.8.x line is not
affected: its older parseHtmlSpecialContent does not amplify, despite sharing the same
case-sensitive indexOf.
Proof of Concept
const { DOMParser, XMLSerializer } = require('@xmldom/xmldom');
const n = 1000;
const payload = '<html><body>' + '<script>x</ScRiPt>'.repeat(n) + '</body></html>';
const doc = new DOMParser().parseFromString(payload, 'text/html');
const out = new XMLSerializer().serializeToString(doc);
console.log(payload.length, out.length, (out.length / payload.length).toFixed(1) + 'x');
// 18026 9037063 501.3x — an 18 KB input yields ~9 MB of output
Output size grows quadratically with the number of case-mismatched raw-text elements:
Repeats | Input len | Output len | Ratio
1 | 44 | 109 | 2.5x
100 | 1826 | 93763 | 51.3x
500 | 9026 | 2268563 | 251.3x
1000 | 18026 | 9037063 | 501.3x
2000 | 36026 | 36074063 | 1001.3x
Proof of Concept from @KarimTantawey (tested with script); the same amplification occurs for style,
textarea, and title.
Impact
Small attacker payloads can force disproportionate CPU and memory usage in services that parse and serialize untrusted HTML via xmldom. The quadratic growth means a modest-sized input (tens of kilobytes) can produce output in the tens or hundreds of megabytes, potentially exhausting memory or causing timeouts.
The attack only requires HTML mode (text/html MIME type) and mixed-case closing tags for
any of the four raw-text element types. No special configuration or error handler setup is needed.
Severity note
The CVSS 4.0 vector scores availability only (VA:H, with VC:N/VI:N): the flaw neither discloses
nor corrupts data, but a small untrusted HTML input (tens of KB) can force output and memory in the
tens to hundreds of MB, enough to exhaust a service's heap…
- Record
GHSA-6mj3-qw4j-hgrw- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-178, CWE-400
- Updated
- 2026-11-02
NVD
8.7
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
- Record
CVE-2026-83612- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/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 - Weakness
- CWE-178, CWE-400
- Updated
- 2026-11-02
OSV
8.7
xmldom: HTML raw-text closing-tag case mismatch causes output amplification
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
- Record
CVE-2026-83612- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-178, CWE-400
- Updated
- 2026-11-02
OSVDEBIAN-CVE-2026-83612
8.7
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
- Record
DEBIAN-CVE-2026-83612- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/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 - Updated
- 2026-11-02
Show 5 moreShow less
OSVGHSA-6mj3-qw4j-hgrw
8.7
xmldom: HTML raw-text closing-tag case mismatch causes output amplification
Summary
In HTML mode (text/html), a raw-text element (script, style, textarea, title) whose closing
tag differs in case from its opening tag (e.g. </ScRiPt> for <script>) is mishandled by the
parser, producing quadratic (O(n²)) output growth — a small crafted document parses and serializes
into output orders of magnitude larger, exhausting CPU and memory. A modest input of tens of KB can
therefore cause a denial of service in any service that parses untrusted HTML with xmldom. Only HTML
mode is affected.
Details
The parser calls parseHtmlSpecialContent for each raw-text element in HTML mode, matched via
isHTMLRawTextElement / isHTMLEscapableRawTextElement (so all four types — script, style,
textarea, title — are in scope). It searches for the element's closing tag with
source.indexOf('</' + tagName + '>', elStartEnd), a byte-for-byte case-sensitive match. A
mixed-case closing tag never matches, so the search returns -1, and the following
source.substring(elStartEnd + 1, -1) extracts text backwards from the start of the document
instead of the element's content. The function then returns -1 to the parse loop, which cannot
advance normally and falls back to character-by-character reprocessing. Every raw-text element
re-captures all source text preceding it, so output grows as O(n²) in the number of such elements.
Root Cause
- Case-sensitive close-tag search (
lib/sax.js:549):source.indexOf('</' + tagName + '>', elStartEnd)does not fold case, contrary to the WHATWG HTML RAWTEXT end-tag-name rule. - Unguarded
-1(lib/sax.js:550):source.substring(elStartEnd + 1, elEndStart)runs even whenelEndStart === -1, extracting text backwards from position 0. - Unstable progression (
lib/sax.js:556): the function returnselEndStart(-1), driving repeated character-by-character fallback in the parse loop.
Affected Versions
Only the 0.9.x line is affected — the amplification was introduced in 0.9.0-beta.1 when
parseHtmlSpecialContent was refactored, and remains through 0.9.11. The 0.8.x line is not
affected: its older parseHtmlSpecialContent does not amplify, despite sharing the same
case-sensitive indexOf.
Proof of Concept
const { DOMParser, XMLSerializer } = require('@xmldom/xmldom');
const n = 1000;
const payload = '<html><body>' + '<script>x</ScRiPt>'.repeat(n) + '</body></html>';
const doc = new DOMParser().parseFromString(payload, 'text/html');
const out = new XMLSerializer().serializeToString(doc);
console.log(payload.length, out.length, (out.length / payload.length).toFixed(1) + 'x');
// 18026 9037063 501.3x — an 18 KB input yields ~9 MB of output
Output size grows quadratically with the number of case-mismatched raw-text elements:
Repeats | Input len | Output len | Ratio
1 | 44 | 109 | 2.5x
100 | 1826 | 93763 | 51.3x
500 | 9026 | 2268563 | 251.3x
1000 | 18026 | 9037063 | 501.3x
2000 | 36026 | 36074063 | 1001.3x
Proof of Concept from @KarimTantawey (tested with script); the same amplification occurs for style,
textarea, and title.
Impact
Small attacker payloads can force disproportionate CPU and memory usage in services that parse and serialize untrusted HTML via xmldom. The quadratic growth means a modest-sized input (tens of kilobytes) can produce output in the tens or hundreds of megabytes, potentially exhausting memory or causing timeouts.
The attack only requires HTML mode (text/html MIME type) and mixed-case closing tags for
any of the four raw-text element types. No special configuration or error handler setup is needed.
Severity note
The CVSS 4.0 vector scores availability only (VA:H, with VC:N/VI:N): the flaw neither discloses
nor corrupts data, but a small untrusted HTML input (tens of KB) can force output and memory in the
tens to hundreds of MB, enough to exhaust a service's heap…
- Record
GHSA-6mj3-qw4j-hgrw- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-178, CWE-400
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-83612
8.7
xmldom is a pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module. From 0.9.0-beta.1 until 0.9.12, HTML-mode parsing through DOMParser.parseFromString() mishandles a mixed-case closing tag for the script, style, textarea, or title raw-text elements. parseHtmlSpecialContent, selected by isHTMLRawTextElement or isHTMLEscapableRawTextElement, uses a case-sensitive indexOf() and then calls substring() with a missing-close result of negative one, causing unstable parser progression and quadratic output amplification. A small untrusted text/html document can consequently consume disproportionate CPU and memory when parsed and serialized. This issue is fixed in @xmldom/xmldom version 0.9.12.
- Record
UBUNTU-CVE-2026-83612- CVSS 4.0
- 8.7 High
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
OSVCLSA-2026-1790608669 No score
TuxCare security update for @xmldom/xmldom (9 CVEs)
TuxCare rebuilt @xmldom/xmldom to address 9 CVEs. Fixed in 0.9.10-tuxcare.1.
- Record
CLSA-2026-1790608669- Updated
- 2026-11-02
OSVCLSA-2026-1791571542 No score
TuxCare security update for @xmldom/xmldom (1 CVE)
TuxCare rebuilt @xmldom/xmldom to address 1 CVE. Fixed in 0.9.8-tuxcare.4.
- Record
CLSA-2026-1791571542- Updated
- 2026-11-02
OSVROOT-APP-NPM-CVE-2026-83612 No score
CVE-2026-83612 in @xmldom/xmldom - Patched by Root
Root has patched CVE-2026-83612 in the @xmldom/xmldom package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-CVE-2026-83612- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@xmldom/xmldomnpm |
0.9.0-beta.1 to 0.9.11 | 0.9.12 |
@xmldom/xmldomTuxCare:npm From an advisory covering 9 CVEs |
0.9.10-tuxcare.0 up to 0.9.10-tuxcare.1, plus listed versions 0.9.10 |
0.9.10-tuxcare.1 |
@xmldom/xmldomTuxCare:npm |
0.9.8-tuxcare.0 up to 0.9.8-tuxcare.4, plus listed versions 0.9.80.9.8-tuxcare.10.9.8-tuxcare.20.9.8-tuxcare.3 |
0.9.8-tuxcare.4 |
node-xmldomDebian:12 |
All versions, plus listed versions 0.8.6-10.9.10-10.9.10-20.9.11-10.9.12-1 Show 5 moreShow less0.9.5-10.9.6-10.9.8-10.9.8-20.9.9-1 |
None known |
node-xmldomDebian:13 |
All versions, plus listed versions 0.9.10-10.9.10-20.9.11-10.9.12-10.9.6-10.9.8-10.9.8-20.9.9-1 |
None known |
node-xmldomDebian:14 |
before 0.9.12-1, plus listed versions 0.9.10-10.9.10-20.9.11-10.9.6-10.9.8-10.9.8-20.9.9-1 |
0.9.12-1 |
@xmldom/xmldomnpm |
0.9.0-beta.1 up to 0.9.12 | 0.9.12 |
@xmldom/xmldomRoot:npm |
before 0.9.11-aikido.1 | 0.9.11-aikido.1 |
@rootio/xmldom__xmldomRoot:npm |
before 0.9.11-root.io.1 | 0.9.11-root.io.1 |
node-xmldomUbuntu:20.04:LTS |
All versions, plus listed versions 0.1.27+ds-10.1.27+ds-1+deb10u2build0.20.04.1 |
None known |
Show 4 moreShow less
| Package | Affected | Fixed |
|---|---|---|
node-xmldomUbuntu:22.04:LTS |
All versions, plus listed versions 0.5.0-10.7.3-10.7.5-10.7.5-1ubuntu0.22.04.1 |
None known |
node-xmldomUbuntu:24.04:LTS |
All versions, plus listed versions 0.8.6-1 |
None known |
node-xmldomUbuntu:26.10 |
All versions, plus listed versions 0.9.8-20.9.10-20.9.11-1 |
None known |
node-xmldomUbuntu:26.04:LTS |
All versions, plus listed versions 0.9.6-10.9.8-10.9.8-2 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, facts | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-83612 is a high vulnerability (CVSS 8.7) in @xmldom Xmldom, published September 1, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.52%, the 44th percentile. Fixed in @xmldom/xmldom 0.9.12.
References
Left out here: the rest of 2 source descriptions. The JSON record has them.