Sep 8, 2026·6 min read·4 visits
Unauthenticated Denial of Service via quadratic output amplification triggered by parsing HTML with case-mismatched closing raw-text tags in xmldom.
A Denial of Service (DoS) vulnerability exists in the xmldom library when parsing HTML-mode documents with mixed-case closing tags for raw-text or escapable raw-text elements like script, style, textarea, or title. This leads to algorithmic complexity issues and quadratic output amplification during DOM serialization.
The @xmldom/xmldom package is a pure JavaScript implementation of the W3C standard DOMParser and XMLSerializer specifications. It is widely used in server-side Node.js environments to parse, manipulate, and serialize XML and HTML documents. Because it runs in server-side applications, any vulnerabilities in its parsing logic can expose the host application to remote attacks.
A denial of service vulnerability, tracked as CVE-2026-83612, arises when the parser processes HTML documents containing specific raw-text or escapable raw-text elements. These elements, which include <script>, <style>, <textarea>, and <title>, are parsed in a dedicated mode designed to read content without evaluating sub-elements. The attack surface is exposed directly through the DOMParser.parseFromString() method when called with the text/html mime type.
An attacker can exploit this vulnerability by submitting a crafted HTML document that contains mismatched casing in the closing tags of these elements. This leads to a severe degradation of performance, causing uncontrolled resource consumption. The flaw affects all versions of the library starting from 0.9.0-beta.1 up to, but not including, 0.9.12.
The root cause of the vulnerability lies in a mismatch between the implementation of xmldom and the WHATWG HTML Specification regarding raw-text elements. The specification states that the closing tag of raw-text and escapable raw-text elements must be matched in a case-insensitive manner. Therefore, tags like </SCRIPT> or </ScRiPt> are valid closing markers for an opening <script> tag.
In vulnerable versions of xmldom, the internal helper function parseHtmlSpecialContent (located in lib/sax.js) attempted to find the end of raw-text elements using a case-sensitive search. It implemented this search via the source.indexOf('</' + tagName + '>', elStartEnd) statement. Because the variable tagName preserved the casing of the opening tag (typically lowercase), the parser failed to find closing tags that utilized mixed-case or uppercase characters, resulting in an index value of -1.
The parsing logic then used this return value directly within the String.prototype.substring() method to slice out the content of the element. In JavaScript, when substring(start, end) receives a negative value for the end parameter, it normalizes that parameter to 0. Furthermore, if the start parameter is greater than the end parameter, the method silently swaps the two arguments.
Consequently, the execution of source.substring(elStartEnd + 1, -1) resolved to source.substring(0, elStartEnd + 1). This behavior caused the parser to extract the entire document from its starting offset up to the opening of the current element, rather than returning an empty string or gracefully handling the missing tag. When serialized, this leading document portion was re-emitted, leading to a quadratic growth of the output size over repeated elements.
The vulnerability is localized within the file lib/sax.js inside the parseHtmlSpecialContent function. Below is an analysis of the vulnerable implementation compared directly against the patched code.
// In vulnerable versions of lib/sax.js
function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
var isEscapableRaw = isHTMLEscapableRawTextElement(tagName);
if (isEscapableRaw || isHTMLRawTextElement(tagName)) {
// Vulnerable case-sensitive search
var elEndStart = source.indexOf('</' + tagName + '>', elStartEnd);
// If elEndStart is -1, substring(elStartEnd + 1, -1) swaps arguments
// and returns source.substring(0, elStartEnd + 1)
var text = source.substring(elStartEnd + 1, elEndStart);
// Text contains the entire document from index 0
}
}// In patched version 0.9.12
function parseHtmlSpecialContent(source, elStartEnd, tagName, entityReplacer, domBuilder) {
var isEscapableRaw = isHTMLEscapableRawTextElement(tagName);
if (isEscapableRaw || isHTMLRawTextElement(tagName)) {
// Escape special regex characters in the tag name
var escapedTagName = tagName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// Perform case-insensitive search using a safe regular expression
var closeTag = new RegExp('</' + escapedTagName + '>', 'ig');
closeTag.lastIndex = elStartEnd;
var match = closeTag.exec(source);
var elEndStart = match ? match.index : -1;
// Introduce an explicit boundary guard to prevent backward slicing
if (elEndStart < 0) {
// Safely exit and delegate recovery to the main parser loop
return elStartEnd + 1;
}
var text = source.substring(elStartEnd + 1, elEndStart);
}
}By replacing the case-sensitive string search with a case-insensitive regular expression, the patch aligns xmldom with the WHATWG specification. The introduction of the boundary guard if (elEndStart < 0) ensures that if no closing tag is found, the function exits immediately and prevents any dangerous parameter swapping in the substring call.
An attacker can exploit this vulnerability if they have the ability to supply arbitrary HTML input to an application that processes it using xmldom. The exploit payload utilizes multiple raw-text elements that contain mismatched closing tags to trigger the quadratic amplification mechanism.
Consider the following raw-text bomb payload:
<html>
<body>
<script>x</ScRiPt>
<script>x</ScRiPt>
<script>x</ScRiPt>
</body>
</html>When the parser processes this markup, the first <script> tag fails to find its closing tag </ScRiPt> due to the case mismatch. The parser back-captures everything from the beginning of the document up to the end of the opening tag. The second <script> tag does the same, capturing the preceding markup which now includes the amplified contents of the first tag.
As the number of elements increases, the size of the parsed text buffer grows quadratically ($O(n^2)$). When the application calls XMLSerializer.serializeToString(), this massive internal buffer is written back to the output string. A payload of 1,000 repeating script blocks can result in an output string that is several hundred times larger than the input, locking the single-threaded Node.js event loop and exhausting system memory.
The concrete impact of CVE-2026-83612 is a severe Denial of Service (DoS) condition on the hosting application. Because Node.js operates on a single-threaded event loop, any operation that consumes excessive CPU cycles or causes heavy garbage collection will block all concurrent requests.
This vulnerability has been assigned a CVSS v4.0 score of 8.7, indicating high severity. The attack vector is Network (AV:N), the complexity is Low (AC:L), and no privileges are required (PR:N). There is no impact on confidentiality or integrity, but the impact on availability is High (VA:H).
If an application parses user-generated HTML in real-time (such as in a rich-text comment parser, an email processing system, or an HTML sanitizer), a remote unauthenticated attacker can submit a relatively small payload (under 50 KB) that exhausts the server's memory, eventually crashing the Node.js process due to Out-of-Memory (OOM) errors.
Remediation requires upgrading the @xmldom/xmldom package to version 0.9.12 or above. This release addresses the root parsing issue and prevents the quadratic amplification loop.
If the library is a transitive dependency (introduced by another package), you can force its resolution using your package manager's override capabilities. For npm, add the following to your package.json:
{
"overrides": {
"@xmldom/xmldom": "^0.9.12"
}
}If an immediate upgrade is not possible, applications should implement input size limits on incoming HTML payloads or sanitize tag names using a pre-parser that standardizes all closing tag casing to lowercase before handing the document to xmldom.
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| Product | Affected Versions | Fixed Version |
|---|---|---|
@xmldom/xmldom xmldom | >= 0.9.0-beta.1 < 0.9.12 | 0.9.12 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-178 / CWE-400 |
| Attack Vector | Network (Unauthenticated) |
| CVSS Score | 8.7 |
| EPSS Score | 0.00301 (22.45th percentile) |
| Impact | Denial of Service (CPU & Memory exhaustion) |
| Exploit Status | Proof-of-Concept Available |
| KEV Status | Not Listed |
The software does not properly handle case sensitivity when parsing raw-text HTML tags, causing a fallback logic error that results in resource exhaustion.
A missing authorization vulnerability (CWE-862) exists in n8n where AI Agent workflows executing as tools bypass the Sub-Workflow Caller Policy settings, allowing authenticated users with agent creation privileges to invoke unauthorized sub-workflows across project boundaries.
A command-line option injection vulnerability in GitPython allows low-privilege or unauthenticated actors to read arbitrary local files. The flaw resides in the TagReference.create() function, which fails to evaluate positional arguments against the library's unsafe-option denylist, enabling the execution of native git commands with injected option flags.
GitPython prior to version 3.1.59 contains a path traversal vulnerability via parameter injection. The clone denylist did not restrict the `--separate-git-dir` option, allowing attackers to write repository metadata to arbitrary system paths.
CVE-2026-72925 is a critical vulnerability in the SWC HTML minifier (@swc/html and swc_html_minifier) where safe Unicode-escaped characters in embedded JSON script tags are normalized into raw, unescaped characters during optimization, causing browser-side HTML injection and Cross-Site Scripting.
A critical logical flaw in the Natural Language Toolkit (NLTK) allows attackers to bypass the application-level directory sandbox. This vulnerability enables unauthenticated directory enumeration and arbitrary local file or SQLite database access.
An improper integrity verification vulnerability exists in the Natural Language Toolkit (NLTK) library up to and including version 3.9.4. The library's download utility writes remote ZIP packages directly to disk and extracts their contents onto the filesystem before executing cryptographic checksum validation. An attacker capable of intercepting or manipulating the download stream can exploit this behavior to perform arbitrary file writes, directory traversal, or execute untrusted serialized content.