GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration
Common Weakness Enumeration

CWE-91

Allowed-with-Review

XML Injection (aka Blind XPath Injection)

Abstraction: Base · Status: Draft

The product does not properly neutralize special elements that are used in XML, allowing attackers to modify the syntax, content, or commands of the XML before it is processed by an end system.

216 vulnerabilities reference this CWE, most recent first.

GHSA-VC42-MGR2-W34R

Vulnerability from github – Published: 2022-05-24 17:03 – Updated: 2024-11-22 18:16
VLAI
Summary
Modoboa is vulnerable to an XML External Entity Injection (XXE)
Details

The modoboa-dmarc plugin 1.1.0 for Modoboa is vulnerable to an XML External Entity Injection (XXE) attack when processing XML data. A remote attacker could exploit this to perform a denial of service against the DMARC reporting functionality, such as by referencing the /dev/random file within XML documents that are emailed to the address in the rua field of the DMARC records of a domain.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "modoboa-dmarc"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.2.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2019-19702"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-04-29T10:19:54Z",
    "nvd_published_at": "2019-12-10T20:15:00Z",
    "severity": "HIGH"
  },
  "details": "The modoboa-dmarc plugin 1.1.0 for Modoboa is vulnerable to an XML External Entity Injection (XXE) attack when processing XML data. A remote attacker could exploit this to perform a denial of service against the DMARC reporting functionality, such as by referencing the /dev/random file within XML documents that are emailed to the address in the rua field of the DMARC records of a domain.",
  "id": "GHSA-vc42-mgr2-w34r",
  "modified": "2024-11-22T18:16:51Z",
  "published": "2022-05-24T17:03:09Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-19702"
    },
    {
      "type": "WEB",
      "url": "https://github.com/modoboa/modoboa-dmarc/issues/38"
    },
    {
      "type": "WEB",
      "url": "https://github.com/modoboa/modoboa-dmarc/commit/14c29e0ad9487bdbe4cc0bd1f8bc711285bf9933"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/modoboa/modoboa-dmarc"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/modoboa-dmarc/PYSEC-2019-105.yaml"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/modoboa/PYSEC-2019-251.yaml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "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",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Modoboa is vulnerable to an XML External Entity Injection (XXE)"
}

GHSA-VMH6-VV2C-7HW5

Vulnerability from github – Published: 2022-05-24 17:28 – Updated: 2023-09-28 15:30
VLAI
Details

yWorks yEd Desktop before 3.20.1 allows code execution via an XSL Transformation when using an XML file in conjunction with a custom stylesheet.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2020-25216"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2020-09-17T19:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "yWorks yEd Desktop before 3.20.1 allows code execution via an XSL Transformation when using an XML file in conjunction with a custom stylesheet.",
  "id": "GHSA-vmh6-vv2c-7hw5",
  "modified": "2023-09-28T15:30:15Z",
  "published": "2022-05-24T17:28:59Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-25216"
    },
    {
      "type": "WEB",
      "url": "https://www.yworks.com/products/yed/download"
    },
    {
      "type": "WEB",
      "url": "https://zigrin.com/advisories/yworks-yed-graph-editor-xslt-remote-code-execution-in-xml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VPJ2-4H83-H98J

Vulnerability from github – Published: 2022-05-24 16:57 – Updated: 2022-12-07 21:30
VLAI
Details

IBM Security Directory Server 6.4.0 does not properly neutralize special elements that are used in XML, allowing attackers to modify the syntax, content, or commands of the XML before it is processed by an end system. IBM X-Force ID: 165812.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2019-4539"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2019-10-02T15:15:00Z",
    "severity": "HIGH"
  },
  "details": "IBM Security Directory Server 6.4.0 does not properly neutralize special elements that are used in XML, allowing attackers to modify the syntax, content, or commands of the XML before it is processed by an end system. IBM X-Force ID: 165812.",
  "id": "GHSA-vpj2-4h83-h98j",
  "modified": "2022-12-07T21:30:30Z",
  "published": "2022-05-24T16:57:42Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-4539"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/165812"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/1077045"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-VR34-HP96-76PP

Vulnerability from github – Published: 2026-09-08 21:02 – Updated: 2026-09-08 21:02
VLAI
Summary
xmldom: requireWellFormed DocType publicId/systemId validation is bypassable via an embedded line terminator
Details

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

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

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.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.9.11"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@xmldom/xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.9.10"
            },
            {
              "fixed": "0.9.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-83618"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-625",
      "CWE-91"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-08T21:02:25Z",
    "nvd_published_at": "2026-09-01T15:17:40Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\nAn embedded line terminator bypasses the `requireWellFormed` serializer check for a `DocumentType`\u0027s\npublicId and systemId. The check was added to fix GHSA-f6ww-3ggp-fr8h; an id whose first line is a\nvalid literal slips past it and is emitted verbatim into the `\u003c!DOCTYPE \u2026\u003e` declaration, so the markup\nafter the line terminator breaks out into the surrounding document. Callers who enabled\n`requireWellFormed` to neutralize DocumentType injection remain exposed.\n\n## Details\n\n`publicId` and `systemId` are stored as raw values **including their surrounding quotes**, and the\n`PubidLiteral`/`SystemLiteral` productions include those quotes. The serializer validates them with\n`g.PubidLiteral_match.test(publicId)` and `g.SystemLiteral_match.test(systemId)`, where both matchers\nare `reg(\u0027^\u0027, \u2026, \u0027$\u0027)` and inherit the `m` flag from xmldom\u0027s shared regexp builder. Under `m`, `$`\nmatches at an interior line terminator, so a value such as `\"valid pubid\"\\n\"\u003e\u003c!ENTITY \u2026\u003e` satisfies\nthe matcher on its first line (`\"valid pubid\"` is a complete `PubidLiteral`) and the whole value \u2014\nincluding the post-newline breakout \u2014 is emitted after `PUBLIC`/`SYSTEM`.\n\n### Root Cause\n\n1. A shared regexp builder compiles anchored productions with the `m` flag.\n2. `^\u2026$` under `m` are line anchors, not string anchors.\n3. A full-string validator built on such a production (`.test()`) accepts any string with one\n   conforming line, so a complete, valid literal on the first line passes even though a line terminator\n   and breakout markup follow. `PubidChar` excluding `\u003c`/`\u003e` does not prevent it \u2014 the breakout is\n   appended *after* the literal, not embedded inside it.\n\nThe triggering line terminators are the ECMAScript `LineTerminator` set: U+000A, U+000D, U+2028, U+2029.\n\n## Affected Versions\n\nOnly `@xmldom/xmldom` 0.9.x is affected. The vulnerable matchers are built by `lib/grammar.js`\u0027s\n`m`-flagged `reg()` builder, and the DocType `publicId`/`systemId` `requireWellFormed` check that\nconsumes them was introduced in 0.9.10 (the GHSA-f6ww-3ggp-fr8h fix); 0.9.10 and 0.9.11 carry it.\n`0.8.x` performs the same `requireWellFormed` check with inline, non-`m` regular expressions and is not\naffected. The unscoped `xmldom` package has no `grammar.js` and no `requireWellFormed` serializer, so\nthere is no check to bypass.\n\n## Proof of Concept\n\n```js\nconst { DOMImplementation, XMLSerializer } = require(\u0027@xmldom/xmldom\u0027);\nconst impl = new DOMImplementation();\n\n// publicId: complete literal on line 1, then newline + breakout\nconst dt = impl.createDocumentType(\u0027html\u0027, \u0027\"valid pubid\"\\n\"\u003e\u003c!ENTITY xxe SYSTEM \"file:///etc/passwd\"\u003e\u0027, \u0027\u0027);\nconst doc = impl.createDocument(null, \u0027root\u0027, dt);\nconsole.log(new XMLSerializer().serializeToString(doc, { requireWellFormed: true }));\n// Observed (no throw):\n//   \u003c!DOCTYPE html PUBLIC \"valid pubid\"\n//   \"\u003e\u003c!ENTITY xxe SYSTEM \"file:///etc/passwd\"\u003e\u003e\u003croot/\u003e\n// Expected: InvalidStateError (publicId is not a valid PubidLiteral).\n// Control: a single-line invalid publicId (\"no-surrounding-quotes\u003c\u003e\") DOES throw InvalidStateError,\n// confirming the check is active and specifically bypassed by the line terminator.\n```\n\n## Impact\n\n- **Bypass of the GHSA-f6ww-3ggp-fr8h mitigation.** Applications that adopted `requireWellFormed:\n  true` to neutralize DocumentType injection remain exposed.\n- **XML structure injection into the DOCTYPE**, including injected markup / entity declarations after\n  the public or system identifier.\n\n## Fix Applied\n\nThe anchored `PubidLiteral`/`SystemLiteral` validators used by the `requireWellFormed`\nserializer no longer treat an interior line terminator as satisfying the `$` anchor, so a `publicId`\nor `systemId` containing any ECMAScript `LineTerminator` (U+000A, U+000D, U+2028, U+2029) is rejected\nwith `InvalidStateError`. Valid single-line identifiers serialize unchanged, and the default\nserialization path is unaffected.\n\n\u003e **\u26a0 Opt-in required.** Protection is not automatic. Existing serialization calls remain vulnerable\n\u003e unless `{ requireWellFormed: true }` is explicitly passed. Applications that serialize untrusted DOM\n\u003e content should audit all `serializeToString()` call sites and add it.\n\n### Proof of Concept - fixed path\n\n```js\nconst { DOMImplementation, XMLSerializer } = require(\u0027@xmldom/xmldom\u0027);\nconst impl = new DOMImplementation();\nconst dt = impl.createDocumentType(\u0027html\u0027, \u0027\"valid pubid\"\\n\"\u003e\u003c!ENTITY xxe SYSTEM \"file:///etc/passwd\"\u003e\u0027, \u0027\u0027);\nconst doc = impl.createDocument(null, \u0027root\u0027, dt);\n\n// Default path (requireWellFormed off) \u2014 unchanged, still emits verbatim:\nconsole.log(new XMLSerializer().serializeToString(doc));\n//   \u003c!DOCTYPE html PUBLIC \"valid pubid\"\n//   \"\u003e\u003c!ENTITY xxe SYSTEM \"file:///etc/passwd\"\u003e\u003e\u003croot/\u003e\n\n// Opt-in path \u2014 now throws instead of emitting the breakout:\nnew XMLSerializer().serializeToString(doc, { requireWellFormed: true });\n//   InvalidStateError: DocumentType publicId is not a valid PubidLiteral\n```\n\n### Why the default stays verbatim\n\nThe W3C DOM Parsing \"require well-formed\" flag defaults to false, and a browser `XMLSerializer` emits\nthe DOCTYPE verbatim. Unconditionally throwing on a malformed `publicId`/`systemId` would be an\nunjustified breaking change to the default path, so the fix tightens only the opt-in\n`requireWellFormed` validator, matching browser and spec defaults.\n\n### Residual limitation\n\nThe guarantee holds only for callers that pass `{ requireWellFormed: true }`; the default\nserialization path still emits `publicId`/`systemId` verbatim. `publicId` and `systemId` are not\nvalidated at creation (`createDocumentType`) or on direct property assignment\n(`documentType.publicId = \u2026`) \u2014 the WHATWG DOM specification places no well-formedness constraint on\nthese fields at creation time, so the serializer is the spec-aligned enforcement point.",
  "id": "GHSA-vr34-hp96-76pp",
  "modified": "2026-09-08T21:02:25Z",
  "published": "2026-09-08T21:02:25Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/security/advisories/GHSA-vr34-hp96-76pp"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-83618"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/pull/1071"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/commit/7b2ec67e1750daadd0bb06c92e875e726544a362"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/xmldom/xmldom"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/releases/tag/0.9.12"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "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",
      "type": "CVSS_V4"
    }
  ],
  "summary": "xmldom: requireWellFormed DocType publicId/systemId validation is bypassable via an embedded line terminator"
}

GHSA-VXVC-4PM5-3RQ9

Vulnerability from github – Published: 2026-09-11 00:31 – Updated: 2026-09-11 00:31
VLAI
Details

IBM webMethods Integration Server 11.1 IBM webMethods Integration is vulnerable to an XML external entity injection (XXE) attack when processing XML data. A remote attacker could exploit this vulnerability to expose sensitive information or consume memory resources.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-2310"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-10T22:16:55Z",
    "severity": "HIGH"
  },
  "details": "IBM webMethods Integration Server 11.1 IBM webMethods Integration is vulnerable to an XML external entity injection (XXE) attack when processing XML data. A remote attacker could exploit this vulnerability to expose sensitive information or consume memory resources.",
  "id": "GHSA-vxvc-4pm5-3rq9",
  "modified": "2026-09-11T00:31:12Z",
  "published": "2026-09-11T00:31:12Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2310"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/7286620"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-W2RR-34G9-RVRJ

Vulnerability from github – Published: 2026-09-08 20:31 – Updated: 2026-09-08 20:31
VLAI
Summary
xmldom: Element name injection via createElement() bypasses requireWellFormed
Details

Summary

Document.createElement() in @xmldom/xmldom accepts arbitrary strings as the tagName parameter with zero validation. The serializer emits the tag name verbatim into XML/HTML output. Critically, the requireWellFormed: true serializer option — the recommended mitigation from CVE-2026-41672, CVE-2026-41674, and CVE-2026-34601 — did NOT catch this, making it a bypass of the existing security controls.

An attacker who controls the element name string can inject arbitrary attributes (including event handlers) into the serialized output, leading to XSS when the output is consumed by a browser or downstream parser.

Details

Document.createElement() accepts any string as tagName and stores it directly on the element node without validation. When the document is later serialized via XMLSerializer.serializeToString(), the serializer emits the tagName verbatim into the output.

The XML specification requires element names to conform to the Name production. The existing createAttributeNS() and createElementNS() methods validate qualified names against an anchored name/QName pattern, but createElement() bypasses this entirely, and the requireWellFormed: true serializer path performed no element-name validation — rendering it ineffective against this vector.

Root Cause

  1. createElement() stores the raw tagName string without any validation.
  2. The serializer's requireWellFormed code path did not validate element names against the XML Name/QName production.
  3. The serializer emits tagName directly into angle brackets: <${tagName}...>.

Proof of Concept

const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom');

const impl = new DOMImplementation();
const serializer = new XMLSerializer();
const doc = impl.createDocument(null, 'root', null);

// Inject an element whose "name" contains attributes with an XSS payload
const el = doc.createElement('img src=x onerror="alert(1)"');
doc.documentElement.appendChild(el);

const output = serializer.serializeToString(doc, { requireWellFormed: true });
console.log(output);
// <root><img src=x onerror="alert(1)"/></root>
//
// A browser parsing this HTML will execute alert(1).
// requireWellFormed: true did NOT prevent the injection.

Impact

Applications that use @xmldom/xmldom to construct DOM trees and serialize them to XML/HTML are vulnerable to injection attacks if any part of an element name originates from user input. This includes:

  • Cross-Site Scripting (XSS): Injecting event handler attributes (onerror, onclick, etc.) into HTML output consumed by browsers.
  • XML injection: Breaking XML document structure by injecting closing tags, new elements, or processing instructions through the element name.
  • Security control bypass: Applications that adopted requireWellFormed: true as a mitigation for CVE-2026-41672 / 41674 / 34601 remained vulnerable through this vector.

@xmldom/xmldom can also be used inside browsers, where it mirrors the DOM API. Unlike the browser's createElement(), which rejects an invalid name with InvalidCharacterError, xmldom accepts it — developers may assume the same safety and skip validation.

Fix Applied

⚠ 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.

When { requireWellFormed: true } is passed, the serializer now validates each element's serialized qualified name against the XML QName production and throws InvalidStateError before emitting the start tag. This also covers the namespace-prefix sub-vector: an invalid prefix surfaces either in the element qualified name (PREFIX:local) or in a synthesized xmlns:PREFIX declaration, and both are QName-checked.

Fixed under requireWellFormed: true in @xmldom/xmldom 0.9.11 and 0.8.14. Default serialization is unchanged.

PoC — fixed path

const { DOMImplementation, XMLSerializer } = require('@xmldom/xmldom');

const doc = new DOMImplementation().createDocument(null, 'root', null);
doc.documentElement.appendChild(doc.createElement('img src=x onerror="alert(1)"'));

// Default (unchanged): verbatim — injection present
console.log(new XMLSerializer().serializeToString(doc));
// <root><img src=x onerror="alert(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 element name "img src=x onerror="alert(1)"" is not a valid XML QName
}

Why the default stays verbatim

The W3C DOM Parsing and Serialization spec defines a require well-formed flag whose default value is false. With the flag unset, the serializer emits element names verbatim, matching the XMLSerializer behavior of Chrome, Firefox, and Safari. Unconditionally throwing would be a behavioral breaking change with no spec justification; the opt-in requireWellFormed: true flag lets applications that require injection safety enable strict mode without breaking existing code.

Residual limitation

createElement(tagName) does not validate tagName at creation time. Enforcing an InvalidCharacterError for invalid names unconditionally at creation time is a breaking change and is deferred to the next breaking release. When the default serialization path is used (without requireWellFormed: true), invalid element names are still emitted verbatim; applications that do not pass requireWellFormed: true remain exposed.

Creation-time validation is tracked in a public issue on the next breaking-release milestone (filed at publication — issue link to be added), targeting the next breaking release.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.9.10"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@xmldom/xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.9.0"
            },
            {
              "fixed": "0.9.11"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.8.13"
      },
      "package": {
        "ecosystem": "npm",
        "name": "@xmldom/xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.7.0"
            },
            {
              "fixed": "0.8.14"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "0.6.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-83607"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-08T20:31:08Z",
    "nvd_published_at": "2026-09-01T15:17:38Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`Document.createElement()` in `@xmldom/xmldom` accepts arbitrary strings as the `tagName` parameter with zero validation. The serializer emits the tag name verbatim into XML/HTML output. Critically, the `requireWellFormed: true` serializer option \u2014 the recommended mitigation from CVE-2026-41672, CVE-2026-41674, and CVE-2026-34601 \u2014 did NOT catch this, making it a bypass of the existing security controls.\n\nAn attacker who controls the element name string can inject arbitrary attributes (including event handlers) into the serialized output, leading to XSS when the output is consumed by a browser or downstream parser.\n\n## Details\n\n`Document.createElement()` accepts any string as `tagName` and stores it directly on the element node without validation. When the document is later serialized via `XMLSerializer.serializeToString()`, the serializer emits the `tagName` verbatim into the output.\n\nThe XML specification requires element names to conform to the `Name` production. The existing `createAttributeNS()` and `createElementNS()` methods validate qualified names against an anchored name/`QName` pattern, but `createElement()` bypasses this entirely, and the `requireWellFormed: true` serializer path performed no element-name validation \u2014 rendering it ineffective against this vector.\n\n### Root Cause\n\n1. `createElement()` stores the raw `tagName` string without any validation.\n2. The serializer\u0027s `requireWellFormed` code path did not validate element names against the XML `Name`/`QName` production.\n3. The serializer emits `tagName` directly into angle brackets: `\u003c${tagName}...\u003e`.\n\n## Proof of Concept\n\n```js\nconst { DOMImplementation, XMLSerializer } = require(\u0027@xmldom/xmldom\u0027);\n\nconst impl = new DOMImplementation();\nconst serializer = new XMLSerializer();\nconst doc = impl.createDocument(null, \u0027root\u0027, null);\n\n// Inject an element whose \"name\" contains attributes with an XSS payload\nconst el = doc.createElement(\u0027img src=x onerror=\"alert(1)\"\u0027);\ndoc.documentElement.appendChild(el);\n\nconst output = serializer.serializeToString(doc, { requireWellFormed: true });\nconsole.log(output);\n// \u003croot\u003e\u003cimg src=x onerror=\"alert(1)\"/\u003e\u003c/root\u003e\n//\n// A browser parsing this HTML will execute alert(1).\n// requireWellFormed: true did NOT prevent the injection.\n```\n\n## Impact\n\nApplications that use `@xmldom/xmldom` to construct DOM trees and serialize them to XML/HTML are vulnerable to injection attacks if any part of an element name originates from user input. This includes:\n\n- **Cross-Site Scripting (XSS)**: Injecting event handler attributes (`onerror`, `onclick`, etc.) into HTML output consumed by browsers.\n- **XML injection**: Breaking XML document structure by injecting closing tags, new elements, or processing instructions through the element name.\n- **Security control bypass**: Applications that adopted `requireWellFormed: true` as a mitigation for CVE-2026-41672 / 41674 / 34601 remained vulnerable through this vector.\n\n`@xmldom/xmldom` can also be used inside browsers, where it mirrors the DOM API. Unlike the browser\u0027s `createElement()`, which rejects an invalid name with `InvalidCharacterError`, xmldom accepts it \u2014 developers may assume the same safety and skip validation.\n\n## Fix Applied\n\n\u003e **\u26a0 Opt-in required.** Protection is not automatic. Existing serialization calls remain\n\u003e vulnerable unless `{ requireWellFormed: true }` is explicitly passed. Applications that\n\u003e serialize untrusted DOM content should audit all `serializeToString()` call sites and add it.\n\nWhen `{ requireWellFormed: true }` is passed, the serializer now validates each element\u0027s serialized qualified name against the XML `QName` production and throws `InvalidStateError` before emitting the start tag. This also covers the **namespace-prefix** sub-vector: an invalid prefix surfaces either in the element qualified name (`PREFIX:local`) or in a synthesized `xmlns:PREFIX` declaration, and both are QName-checked.\n\nFixed under `requireWellFormed: true` in `@xmldom/xmldom` **0.9.11** and **0.8.14**. Default serialization is unchanged.\n\n### PoC \u2014 fixed path\n\n```js\nconst { DOMImplementation, XMLSerializer } = require(\u0027@xmldom/xmldom\u0027);\n\nconst doc = new DOMImplementation().createDocument(null, \u0027root\u0027, null);\ndoc.documentElement.appendChild(doc.createElement(\u0027img src=x onerror=\"alert(1)\"\u0027));\n\n// Default (unchanged): verbatim \u2014 injection present\nconsole.log(new XMLSerializer().serializeToString(doc));\n// \u003croot\u003e\u003cimg src=x onerror=\"alert(1)\"/\u003e\u003c/root\u003e\n\n// Opt-in guard: throws InvalidStateError before serializing\ntry {\n  new XMLSerializer().serializeToString(doc, { requireWellFormed: true });\n} catch (e) {\n  console.log(e.name, e.message);\n  // InvalidStateError: The element name \"img src=x onerror=\"alert(1)\"\" is not a valid XML QName\n}\n```\n\n### Why the default stays verbatim\n\nThe W3C DOM Parsing and Serialization spec defines a `require well-formed` flag whose **default value is `false`**. With the flag unset, the serializer emits element names verbatim, matching the `XMLSerializer` behavior of Chrome, Firefox, and Safari. Unconditionally throwing would be a behavioral breaking change with no spec justification; the opt-in `requireWellFormed: true` flag lets applications that require injection safety enable strict mode without breaking existing code.\n\n### Residual limitation\n\n`createElement(tagName)` does not validate `tagName` at creation time. Enforcing an `InvalidCharacterError` for invalid names unconditionally at creation time is a breaking change and is deferred to the next breaking release. When the default serialization path is used (without `requireWellFormed: true`), invalid element names are still emitted verbatim; applications that do not pass `requireWellFormed: true` remain exposed.\n\nCreation-time validation is tracked in a public issue on the next breaking-release milestone (filed at publication \u2014 issue link to be added), targeting the next breaking release.",
  "id": "GHSA-w2rr-34g9-rvrj",
  "modified": "2026-09-08T20:31:08Z",
  "published": "2026-09-08T20:31:08Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/security/advisories/GHSA-w2rr-34g9-rvrj"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-83607"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/pull/1043"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/pull/1050"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/commit/cba1321218b069182695813fa7565653708e172e"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/commit/d8212e632507eaf1d9f609657dd4c56abeb12d44"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/xmldom/xmldom"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/releases/tag/0.8.14"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/releases/tag/0.9.11"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "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",
      "type": "CVSS_V4"
    }
  ],
  "summary": "xmldom: Element name injection via createElement() bypasses requireWellFormed"
}

GHSA-W53C-VMPF-RRJ7

Vulnerability from github – Published: 2022-05-14 03:02 – Updated: 2022-05-14 03:02
VLAI
Details

Openpsa contains a XML Injection vulnerability in RSS file upload feature that can result in Remote denial of service. This attack appear to be exploitable via Specially crafted XML file. This vulnerability appears to have been fixed in after commit 4974a26.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2018-1000526"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2018-06-26T16:29:00Z",
    "severity": "HIGH"
  },
  "details": "Openpsa contains a XML Injection vulnerability in RSS file upload feature that can result in Remote denial of service. This attack appear to be exploitable via Specially crafted XML file. This vulnerability appears to have been fixed in after commit 4974a26.",
  "id": "GHSA-w53c-vmpf-rrj7",
  "modified": "2022-05-14T03:02:50Z",
  "published": "2022-05-14T03:02:50Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2018-1000526"
    },
    {
      "type": "WEB",
      "url": "https://github.com/flack/openpsa/issues/192"
    },
    {
      "type": "WEB",
      "url": "https://0dd.zone/2018/05/31/OpenPSA-Object-Injection"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-WH42-8R2W-873X

Vulnerability from github – Published: 2023-06-15 21:30 – Updated: 2025-03-04 18:03
VLAI
Summary
Magento Open Source allows XML Injection
Details

Adobe Commerce versions 2.4.6 (and earlier), 2.4.5-p2 (and earlier) and 2.4.4-p3 (and earlier) are affected by an XML Injection vulnerability. An attacker with low privileges can trigger a specially crafted script to a security feature bypass. Exploitation of this issue does not require user interaction.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "magento/community-edition"
      },
      "versions": [
        "2.4.6"
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "magento/community-edition"
      },
      "versions": [
        "2.4.5"
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "magento/community-edition"
      },
      "versions": [
        "2.4.4"
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "magento/community-edition"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.4.5-p1"
            },
            {
              "fixed": "2.4.5-p3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "magento/community-edition"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.4.4-p1"
            },
            {
              "fixed": "2.4.4-p4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "magento/project-community-edition"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "2.0.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-29289"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-03-04T18:02:59Z",
    "nvd_published_at": "2023-06-15T19:15:10Z",
    "severity": "MODERATE"
  },
  "details": "Adobe Commerce versions 2.4.6 (and earlier), 2.4.5-p2 (and earlier) and 2.4.4-p3 (and earlier) are affected by an XML Injection vulnerability. An attacker with low privileges can trigger a specially crafted script to a security feature bypass. Exploitation of this issue does not require user interaction.",
  "id": "GHSA-wh42-8r2w-873x",
  "modified": "2025-03-04T18:03:00Z",
  "published": "2023-06-15T21:30:25Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-29289"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/magento/magento2"
    },
    {
      "type": "WEB",
      "url": "https://helpx.adobe.com/security/products/magento/apsb23-35.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:U",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Magento Open Source allows XML Injection"
}

GHSA-WH4C-J3R5-MJHP

Vulnerability from github – Published: 2026-04-01 00:19 – Updated: 2026-04-24 23:17
VLAI
Summary
xmldom: XML injection via unsafe CDATA serialization allows attacker-controlled markup insertion
Details

Summary

@xmldom/xmldom allows attacker-controlled strings containing the CDATA terminator ]]> to be inserted into a CDATASection node. During serialization, XMLSerializer emitted the CDATA content verbatim without rejecting or safely splitting the terminator. As a result, data intended to remain text-only became active XML markup in the serialized output, enabling XML structure injection and downstream business-logic manipulation.

The sequence ]]> is not allowed inside CDATA content and must be rejected or safely handled during serialization. (MDN Web Docs)

Attack surface

Document.createCDATASection(data) is the most direct entry point, but it is not the only one. The WHATWG DOM spec intentionally does not validate ]]> in mutation methods — only createCDATASection carries that guard. The following paths therefore also allow ]]> to enter a CDATASection node and reach the serializer:

  • CharacterData.appendData()
  • CharacterData.replaceData()
  • CharacterData.insertData()
  • Direct assignment to .data
  • Direct assignment to .textContent

(Note: assigning to .nodeValue does not update .data in this implementation — the serializer reads .data directly — so .nodeValue is not an exploitable path.)

Parse path

Parsing XML that contains a CDATA section is not affected. The SAX parser's non-greedy CDSect regex stops at the first ]]>, so parsed CDATA data never contains the terminator.


Impact

If an application uses xmldom to generate "trusted" XML documents that embed untrusted user input inside CDATA (a common pattern in exports, feeds, SOAP/XML integrations, etc.), an attacker can inject additional XML elements/attributes into the generated document.

This can lead to:

  • Integrity violation of generated XML documents.
  • Business-logic injection in downstream consumers (e.g., injecting <approved>true</approved>, <role>admin</role>, workflow flags, or other security-relevant elements).
  • Unexpected privilege/workflow decisions if downstream logic assumes injected nodes cannot appear.

This issue does not require malformed parsers or browser behavior; it is caused by serialization producing attacker-influenced XML markup.


Root Cause (with file + line numbers)

File: lib/dom.js

1. No validation in createCDATASection

createCDATASection: function (data) accepts any string and appends it directly.

  • Lines 2216–2221 (0.9.8)

2. Unsafe CDATA serialization

Serializer prints CDATA sections as:

<![CDATA[ + node.data + ]]>

without handling ]]> in the data.

  • Lines 2919–2920 (0.9.8)

Because CDATA content is emitted verbatim, an embedded ]]> closes the CDATA section early and the remainder of the attacker-controlled payload is interpreted as markup in the serialized XML.


Proof of Concept — Fix A: createCDATASection now throws

On patched versions, passing ]]> directly to createCDATASection throws InvalidCharacterError instead of silently accepting the payload:

const { DOMImplementation } = require('./lib');

const doc = new DOMImplementation().createDocument(null, 'root', null);
try {
  doc.createCDATASection('SAFE]]><injected attr="pwn"/>');
  console.log('VULNERABLE — no error thrown');
} catch (e) {
  console.log('FIXED — threw:', e.name); // InvalidCharacterError
}

Expected output on patched versions:

FIXED — threw: InvalidCharacterError

Proof of Concept — Fix B: mutation vector now safe

On patched versions, injecting ]]> via a mutation method (appendData, replaceData, .data =, .textContent =) no longer produces injectable output. The serializer splits the terminator so the result round-trips as safe text:

const { DOMImplementation, XMLSerializer } = require('./lib');
const { DOMParser } = require('./lib');

const doc = new DOMImplementation().createDocument(null, 'root', null);

// Start with safe data, then mutate to include the terminator
const cdata = doc.createCDATASection('safe');
doc.documentElement.appendChild(cdata);
cdata.appendData(']]><injected attr="pwn"/><more>TEXT</more><![CDATA[');

const out = new XMLSerializer().serializeToString(doc);
console.log('Serialized:', out);

const reparsed = new DOMParser().parseFromString(out, 'text/xml');
const injected = reparsed.getElementsByTagName('injected').length > 0;
console.log('Injected element found in reparsed doc:', injected);
// VULNERABLE: true  |  FIXED: false

Expected output on patched versions:

Serialized: <root><![CDATA[safe]]]]><![CDATA[><injected attr="pwn"/><more>TEXT</more><![CDATA[]]></root>
Injected element found in reparsed doc: false

Fix Applied

Both mitigations were implemented:

Option A — Strict/spec-aligned: reject ]]> in createCDATASection()

Document.createCDATASection(data) now throws InvalidCharacterError (per the WHATWG DOM spec) when data contains ]]>. This closes the direct entry point.

Code that previously passed a string containing ]]> to createCDATASection and relied on the silent/unsafe behaviour will now receive InvalidCharacterError. Use a mutation method such as appendData if you intentionally need ]]> in a CDATASection node's data (the serializer split in Option B will keep the output safe).

Option B — Defensive serialization: split the terminator during serialization

XMLSerializer now replaces every occurrence of ]]> in CDATA section data with the split sequence ]]]]><![CDATA[> before emitting. This closes all mutation-vector paths that Option A alone cannot guard, and means the serialized output is always well-formed XML regardless of how ]]> entered the node.

Update — 2026-04-xx (0.9.10 / 0.8.13)

splitCDATASections is deprecated

The CDATA split behavior introduced as Option B of this fix (replacing ]]> with]]]]><![CDATA[> during serialization) is deprecated as of 0.9.10 / 0.8.13.

This release introduces a requireWellFormed option on XMLSerializer.serializeToString(). When { requireWellFormed: true } is passed as the second argument, the serializer throws InvalidStateError if CDATA section data contains ]]> — this is the spec-aligned behavior (W3C DOM Parsing and Serialization, require well-formed flag) and the recommended migration path going forward. The split behavior is now controlled by an explicit splitCDATASections option (default true, preserving the current behavior). The three serialization behaviors are: | requireWellFormed | splitCDATASections | Behavior ||---|---|---|| false (default) | true (default) | Split ]]>]]]]><![CDATA[> (current behavior, deprecated) || true | — (ignored) | Throw InvalidStateError — spec-aligned, recommended |\ false | false | Emit verbatim — same as pre-0.9.9 behavior |

requireWellFormed: true takes precedence: the split path is unreachable when it is set.

Migration

Replace any reliance on the default split behavior with an explicit opt-in: ```js// Before (implicit split, deprecated): const xml = new XMLSerializer().serializeToString(doc);

// After (explicit guard, spec-aligned): const xml = new XMLSerializer().serializeToString(doc, { requireWellFormed: true }); // Throws InvalidStateError if any CDATASection contains ']]>' ```

Removal timeline

Both the splitCDATASections option and the underlying ]]>]]]]><![CDATA[> split mechanics will be removed in the next breaking (0.10.0) release. After removal, the only behaviors will be verbatim (default) and requireWellFormed: true (throws).

Removal is tracked in xmldom/xmldom#999.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "last_affected": "0.6.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@xmldom/xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.8.12"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "npm",
        "name": "@xmldom/xmldom"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.9.0"
            },
            {
              "fixed": "0.9.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34601"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-91"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-01T00:19:06Z",
    "nvd_published_at": "2026-04-02T18:16:31Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\n`@xmldom/xmldom` allows attacker-controlled strings containing the CDATA terminator `]]\u003e` to be inserted into a `CDATASection` node. During serialization, `XMLSerializer` emitted the CDATA content verbatim without rejecting or safely splitting the terminator. As a result, data intended to remain text-only became **active XML markup** in the serialized output, enabling XML structure\ninjection and downstream business-logic manipulation.\n\nThe sequence `]]\u003e` is not allowed inside CDATA content and must be rejected or safely handled during serialization. ([MDN Web Docs](https://developer.mozilla.org/))\n\n### Attack surface\n\n`Document.createCDATASection(data)` is the most direct entry point, but it is not the only one. The WHATWG DOM spec intentionally does not validate `]]\u003e` in mutation methods \u2014 only `createCDATASection` carries that guard. The following paths therefore also allow `]]\u003e` to enter a CDATASection node and reach the serializer:\n\n- `CharacterData.appendData()`\n- `CharacterData.replaceData()`\n- `CharacterData.insertData()`\n- Direct assignment to `.data`\n- Direct assignment to `.textContent`\n\n(Note: assigning to `.nodeValue` does **not** update `.data` in this implementation \u2014 the serializer reads `.data` directly \u2014 so `.nodeValue` is not an exploitable path.)\n\n### Parse path\n\nParsing XML that contains a CDATA section is **not** affected. The SAX parser\u0027s non-greedy `CDSect` regex stops at the first `]]\u003e`, so parsed CDATA data never contains the terminator.\n\n---\n\n## Impact\n\nIf an application uses `xmldom` to generate \"trusted\" XML documents that embed **untrusted user input** inside CDATA (a common pattern in exports, feeds, SOAP/XML integrations, etc.), an attacker can inject additional XML elements/attributes into the generated document.\n\nThis can lead to:\n\n- Integrity violation of generated XML documents.\n- Business-logic injection in downstream consumers (e.g., injecting `\u003capproved\u003etrue\u003c/approved\u003e`,  `\u003crole\u003eadmin\u003c/role\u003e`, workflow flags, or other security-relevant elements).\n- Unexpected privilege/workflow decisions if downstream logic assumes injected nodes cannot appear.\n\nThis issue does **not** require malformed parsers or browser behavior; it is caused by serialization producing attacker-influenced XML markup.\n\n---\n\n## Root Cause (with file + line numbers)\n\n**File:** `lib/dom.js`\n\n### 1. No validation in `createCDATASection`\n\n`createCDATASection: function (data)` accepts any string and appends it directly.\n\n- **Lines 2216\u20132221** (0.9.8)\n\n### 2. Unsafe CDATA serialization\n\nSerializer prints CDATA sections as:\n\n```\n\u003c![CDATA[ + node.data + ]]\u003e\n```\n\nwithout handling `]]\u003e` in the data.\n\n- **Lines 2919\u20132920** (0.9.8)\n\nBecause CDATA content is emitted verbatim, an embedded `]]\u003e` closes the CDATA section early and the remainder of the attacker-controlled payload is interpreted as markup in the serialized XML.\n\n---\n\n## Proof of Concept \u2014 Fix A: `createCDATASection` now throws\n\nOn patched versions, passing `]]\u003e` directly to `createCDATASection` throws `InvalidCharacterError` instead of silently accepting the payload:\n\n```js\nconst { DOMImplementation } = require(\u0027./lib\u0027);\n\nconst doc = new DOMImplementation().createDocument(null, \u0027root\u0027, null);\ntry {\n  doc.createCDATASection(\u0027SAFE]]\u003e\u003cinjected attr=\"pwn\"/\u003e\u0027);\n  console.log(\u0027VULNERABLE \u2014 no error thrown\u0027);\n} catch (e) {\n  console.log(\u0027FIXED \u2014 threw:\u0027, e.name); // InvalidCharacterError\n}\n```\n\nExpected output on patched versions:\n\n```\nFIXED \u2014 threw: InvalidCharacterError\n```\n\n---\n\n## Proof of Concept \u2014 Fix B: mutation vector now safe\n\nOn patched versions, injecting `]]\u003e` via a mutation method (`appendData`, `replaceData`, `.data =`, `.textContent =`) no longer produces injectable output. The serializer splits the terminator so the result round-trips as safe text:\n\n```js\nconst { DOMImplementation, XMLSerializer } = require(\u0027./lib\u0027);\nconst { DOMParser } = require(\u0027./lib\u0027);\n\nconst doc = new DOMImplementation().createDocument(null, \u0027root\u0027, null);\n\n// Start with safe data, then mutate to include the terminator\nconst cdata = doc.createCDATASection(\u0027safe\u0027);\ndoc.documentElement.appendChild(cdata);\ncdata.appendData(\u0027]]\u003e\u003cinjected attr=\"pwn\"/\u003e\u003cmore\u003eTEXT\u003c/more\u003e\u003c![CDATA[\u0027);\n\nconst out = new XMLSerializer().serializeToString(doc);\nconsole.log(\u0027Serialized:\u0027, out);\n\nconst reparsed = new DOMParser().parseFromString(out, \u0027text/xml\u0027);\nconst injected = reparsed.getElementsByTagName(\u0027injected\u0027).length \u003e 0;\nconsole.log(\u0027Injected element found in reparsed doc:\u0027, injected);\n// VULNERABLE: true  |  FIXED: false\n```\n\nExpected output on patched versions:\n\n```\nSerialized: \u003croot\u003e\u003c![CDATA[safe]]]]\u003e\u003c![CDATA[\u003e\u003cinjected attr=\"pwn\"/\u003e\u003cmore\u003eTEXT\u003c/more\u003e\u003c![CDATA[]]\u003e\u003c/root\u003e\nInjected element found in reparsed doc: false\n```\n\n---\n\n## Fix Applied\n\nBoth mitigations were implemented:\n\n### Option A \u2014 Strict/spec-aligned: reject `]]\u003e` in `createCDATASection()`\n\n`Document.createCDATASection(data)` now throws `InvalidCharacterError` (per the [WHATWG DOM spec](https://dom.spec.whatwg.org/#dom-document-createcdatasection)) when `data` contains `]]\u003e`. This closes the direct entry point.\n\nCode that previously passed a string containing `]]\u003e` to `createCDATASection` and relied on the silent/unsafe behaviour will now receive `InvalidCharacterError`. Use a mutation method such as `appendData` if you intentionally need `]]\u003e` in a CDATASection node\u0027s data (the serializer split in Option B will keep the output safe).\n\n### Option B \u2014 Defensive serialization: split the terminator during serialization\n\n`XMLSerializer` now replaces every occurrence of `]]\u003e` in CDATA section data with the split sequence `]]]]\u003e\u003c![CDATA[\u003e` before emitting. This closes all mutation-vector paths that Option A alone cannot guard, and means the serialized output is always well-formed XML regardless of how `]]\u003e` entered the node.\n\n## Update \u2014 2026-04-xx (0.9.10 / 0.8.13)\n\n### `splitCDATASections` is deprecated\n\nThe CDATA split behavior introduced as Option B of this fix (replacing `]]\u003e` with`]]]]\u003e\u003c![CDATA[\u003e` during serialization) is **deprecated** as of 0.9.10 / 0.8.13.\n\nThis release introduces a `requireWellFormed` option on `XMLSerializer.serializeToString()`. When `{ requireWellFormed: true }` is passed as the second argument, the serializer throws `InvalidStateError` if CDATA section data contains `]]\u003e` \u2014 this is the spec-aligned behavior (W3C DOM Parsing and Serialization, `require well-formed` flag) and the recommended migration path going forward.\nThe split behavior is now controlled by an explicit `splitCDATASections` option (default `true`, preserving the current behavior). The three serialization behaviors are:\n| `requireWellFormed` | `splitCDATASections` | Behavior ||---|---|---|| `false` (default) | `true` (default) | Split `]]\u003e` \u2192 `]]]]\u003e\u003c![CDATA[\u003e` (current behavior, deprecated) || `true` | \u2014 (ignored) | Throw `InvalidStateError` \u2014 spec-aligned, recommended |\\ `false` | `false` | Emit verbatim \u2014 same as pre-0.9.9 behavior |\n\n`requireWellFormed: true` takes precedence: the split path is unreachable when it is set.\n\n### Migration\nReplace any reliance on the default split behavior with an explicit opt-in:\n```js// Before (implicit split, deprecated): const xml = new XMLSerializer().serializeToString(doc);\n\n// After (explicit guard, spec-aligned): const xml = new XMLSerializer().serializeToString(doc, { requireWellFormed: true }); // Throws InvalidStateError if any CDATASection contains \u0027]]\u003e\u0027 ```\n\n### Removal timeline\nBoth the `splitCDATASections` option and the underlying `]]\u003e` \u2192 `]]]]\u003e\u003c![CDATA[\u003e` split mechanics will be removed in the next breaking (`0.10.0`) release. After removal, the only behaviors will be verbatim (default) and `requireWellFormed: true` (throws).\n\nRemoval is tracked in [xmldom/xmldom#999](https://github.com/xmldom/xmldom/issues/999).",
  "id": "GHSA-wh4c-j3r5-mjhp",
  "modified": "2026-04-24T23:17:44Z",
  "published": "2026-04-01T00:19:06Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/security/advisories/GHSA-wh4c-j3r5-mjhp"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34601"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/commit/2b852e836ab86dbbd6cbaf0537f584dd0b5ac184"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/xmldom/xmldom"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/releases/tag/0.8.12"
    },
    {
      "type": "WEB",
      "url": "https://github.com/xmldom/xmldom/releases/tag/0.9.9"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "xmldom: XML injection via unsafe CDATA serialization allows attacker-controlled markup insertion"
}

GHSA-WHJ6-8XVC-HMJM

Vulnerability from github – Published: 2022-05-24 22:29 – Updated: 2022-06-01 00:00
VLAI
Details

A heap-based buffer overflow vulnerability exists in the XML Decompression EnumerationUncompressor::UncompressItem functionality of AT&T Labs’ Xmill 0.7. A specially crafted XMI file can lead to remote code execution. An attacker can provide a malicious file to trigger this vulnerability.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-21829"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-787",
      "CWE-91"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-08-13T19:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "A heap-based buffer overflow vulnerability exists in the XML Decompression EnumerationUncompressor::UncompressItem functionality of AT\u0026T Labs\u2019 Xmill 0.7. A specially crafted XMI file can lead to remote code execution. An attacker can provide a malicious file to trigger this vulnerability.",
  "id": "GHSA-whj6-8xvc-hmjm",
  "modified": "2022-06-01T00:00:24Z",
  "published": "2022-05-24T22:29:03Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-21829"
    },
    {
      "type": "WEB",
      "url": "https://talosintelligence.com/vulnerability_reports/TALOS-2021-1292"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation MIT-5
Implementation

Strategy: Input Validation

  • 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.
CAPEC-250: XML Injection

An attacker utilizes crafted XML user-controllable input to probe, attack, and inject data into the XML database, using techniques similar to SQL injection. The user-controllable input can allow for unauthorized viewing of data, bypassing authentication or the front-end application for direct XML database access, and possibly altering database information.

CAPEC-83: XPath Injection

An attacker can craft special user-controllable input consisting of XPath expressions to inject the XML database and bypass authentication or glean information that they normally would not be able to. XPath Injection enables an attacker to talk directly to the XML database, thus bypassing the application completely. XPath Injection results from the failure of an application to properly sanitize input used as part of dynamic XPath expressions used to query an XML database.