GHSA-6mj3-qw4j-hgrw CVE-2026-83612
xmldom: HTML raw-text closing-tag case mismatch causes output amplification
- Severity
- 0.0 / 10
- High · CVSS 4.0
- Exploit chance (EPSS)
- 0.52%
- Chance of exploitation in the next 30 days. Higher than 44.45% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Fix
0.9.12- Upgrade @xmldom/xmldom to this version or later
Description
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 or stall its event loop. It is reachable
with no authentication, configuration, or error-handler setup — only that the application parses
untrusted text/html and serializes the result.
Fix Applied
The raw-text closing tag is now matched case-insensitively in HTML raw-text mode (per the WHATWG HTML RAWTEXT end-tag rule), and a missing closing tag is handled explicitly, removing the quadratic output amplification. Output for well-formed input is unchanged. Non-breaking; 0.9.x-only.
Affected versions
npm
| Package | Vulnerable | Fixed in |
|---|---|---|
| @xmldom/xmldom | >= 0.9.0-beta.1, < 0.9.12 |
0.9.12 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
@xmldom/xmldom npm → 0.9.12
- npm
npm install @xmldom/xmldom@0.9.12- yarn
yarn add @xmldom/xmldom@0.9.12- pnpm
pnpm add @xmldom/xmldom@0.9.12
Severity breakdown
CVSS 4.0 0.0
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
- Attack vector
- Network
- Attack complexity
- Low
- Attack requirements
- None
- Privileges required
- None
- User interaction
- None
- Confidentiality (vulnerable system)
- None
- Integrity (vulnerable system)
- None
- Availability (vulnerable system)
- High
- Confidentiality (subsequent systems)
- None
- Integrity (subsequent systems)
- None
- Availability (subsequent systems)
- None
Weakness
CWE-178: Improper Handling of Case Sensitivity
The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results.
How to prevent it
- Architecture and Design: Avoid making decisions based on names of resources (e.g. files) if those resources can have alternate names.
- Implementation: Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does. When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue." Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
- Implementation: Inputs should be decoded and canonicalized to the application's current internal representation before being validated (CWE-180). Make sure that the application does not decode the same input twice (CWE-174). Such errors could be used to bypass allowlist validation schemes by introducing dangerous inputs after they have been checked.
CWE-400: Uncontrolled Resource Consumption
The product does not properly control the allocation and maintenance of a limited resource.
How to prevent it
- Architecture and Design: Design throttling mechanisms into the system architecture. The best protection is to limit the amount of resources that an unauthorized user can cause to be expended. A strong authentication and access control model will help prevent such attacks from occurring in the first place. The login application should be protected against DoS attacks as much as possible. Limiting the database access, perhaps by caching result sets, can help minimize the resources expended. To further limit the potential for a DoS attack, consider tracking the rate of requests received from users and blocking requests that exceed a defined rate threshold.
- Architecture and Design: Mitigation of resource exhaustion attacks requires that the target system either: recognizes the attack and denies that user further access for a given amount of time, or uniformly throttles all requests in order to make it more difficult to consume resources more quickly than they can again be freed. The first of these solutions is an issue in itself though, since it may allow attackers to prevent the use of the system by a particular valid user. If the attacker impersonates the valid user, they may be able to prevent the user from accessing the server in question. The second solution is simply difficult to effectively institute -- and even when properly done, it does not provide a full solution. It simply makes the attack require more resources on the part of the attacker.
- Architecture and Design: Ensure that protocols have specific limits of scale placed on them.
- Implementation: Ensure that all failures in resource allocation place the system into a safe posture.
References
Advisories
Packages
Other links
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-x4fp-j954-r2f4 xmldom: End-tag Whitespace-Trim Regex ReDoS — quadratic backtracking in the 0.8.x end-tag parser | High | Also affects @xmldom/xmldom |
| GHSA-vr34-hp96-76pp xmldom: requireWellFormed DocType publicId/systemId validation is bypassable via an embedded line terminator | High | Also affects @xmldom/xmldom |
| GHSA-jxjr-3g7g-3944 xmldom: requireWellFormed element/attribute name validation is bypassable via an embedded line terminator | High | Also affects @xmldom/xmldom |
| GHSA-c7q8-3ch8-vqpv xmldom: Processing Instruction Target Injection Bypasses requireWellFormed | High | Also affects @xmldom/xmldom |
| GHSA-965w-775f-mr7g xmldom: Quadratic-memory consumption | High | Also affects @xmldom/xmldom |
| GHSA-93r5-fhx6-vmg9 xmldom: Quadratic-time parsing via the malformed-input recovery path — `parseElementStartPart` re-scan and `normalize()` adjacent-text merge | High | Also affects @xmldom/xmldom |
| GHSA-8344-3jmq-59r6 xmldom: Quadratic-time attribute deduplication | High | Also affects @xmldom/xmldom |
| GHSA-6h8r-xr42-gp59 xmldom: Parser silently accepts a not-well-formed end tag whose name is followed by a line break and trailing content | Medium | Also affects @xmldom/xmldom |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor