CVE-2026-66295 (GCVE-0-2026-66295)
Vulnerability from cvelistv5 – Published: 2026-11-06 10:16 – Updated: 2026-11-06 10:16
VLAI
EPSS
VEX
Title
Processing instruction target and content emitted unescaped in Saxy encoder allows XML injection
Summary
Saxy's XML encoder writes the target and the content of a processing instruction into the output document verbatim, without validation or escaping. The encoder builds the construct by concatenating both fields between <? and ?>, so neither field is checked against the constraints the XML specification places on it.
Because ?> terminates a processing instruction, a target or content value containing that sequence closes the construct at a position the attacker chooses. Everything the attacker writes after it is emitted as ordinary markup at document level, which allows arbitrary elements, attributes, and further processing instructions to be injected into the serialized document. Appending a matching <? keeps the encoder's own terminator well-formed, so the result still parses and the injection is silent rather than a visible corruption. The target is additionally unconstrained by the XML Name production, which permits injection before the remainder of the processing instruction.
The result is XML injection into a serialized document: the tree the application asks Saxy to encode and the tree a downstream parser reads back are no longer the same. Character data, attribute values, and comments are all escaped by the encoder, so processing instructions are the one construct that passes user bytes through untouched. Since Saxy.XML.processing_instruction/2 is a documented public builder, an application inherits the flaw without misusing the API. The consequences depend on what consumes the XML: forged records in a feed or export read by another system, injected stylesheet or rendering directives, or active content where the output is served to a browser as XML or SVG.
This issue affects saxy: from 0.7.0 before 1.7.0.
Severity
CWE
- CWE-91 - XML Injection
Assigner
EEF
CNA
References
5 references
| URL | Tags |
|---|---|
| https://github.com/qcam/saxy/security/advisories/… | vendor-advisoryrelated |
| https://cna.erlef.org/cves/CVE-2026-66295.html | related |
| https://osv.dev/vulnerability/EEF-CVE-2026-66295 | related |
| https://github.com/qcam/saxy/commit/7266632e94078… | related |
| https://github.com/qcam/saxy/commit/4aeb80e2acc31… | patch |
Impacted products
{
"containers": {
"cna": {
"affected": [
{
"collectionURL": "https://repo.hex.pm",
"cpes": [
"cpe:2.3:a:qcam:saxy:*:*:*:*:*:*:*:*"
],
"defaultStatus": "unaffected",
"modules": [
"\u0027Elixir.Saxy\u0027",
"\u0027Elixir.Saxy.Encoder\u0027",
"\u0027Elixir.Saxy.XML\u0027"
],
"packageName": "saxy",
"packageURL": "pkg:hex/saxy",
"product": "saxy",
"programFiles": [
"lib/saxy.ex",
"lib/saxy/encoder.ex",
"lib/saxy/xml.ex"
],
"programRoutines": [
{
"name": "\u0027Elixir.Saxy\u0027:encode!/2"
},
{
"name": "\u0027Elixir.Saxy\u0027:encode_to_iodata!/2"
},
{
"name": "\u0027Elixir.Saxy.Encoder\u0027:encode_to_iodata/2"
},
{
"name": "\u0027Elixir.Saxy.XML\u0027:processing_instruction/2"
}
],
"repo": "https://github.com/qcam/saxy",
"vendor": "qcam",
"versions": [
{
"lessThan": "1.7.0",
"status": "affected",
"version": "0.7.0",
"versionType": "semver"
}
]
},
{
"collectionURL": "https://github.com",
"cpes": [
"cpe:2.3:a:qcam:saxy:*:*:*:*:*:*:*:*"
],
"defaultStatus": "unaffected",
"modules": [
"\u0027Elixir.Saxy\u0027",
"\u0027Elixir.Saxy.Encoder\u0027",
"\u0027Elixir.Saxy.XML\u0027"
],
"packageName": "qcam/saxy",
"packageURL": "pkg:github/qcam/saxy",
"product": "saxy",
"programFiles": [
"lib/saxy.ex",
"lib/saxy/encoder.ex",
"lib/saxy/xml.ex"
],
"programRoutines": [
{
"name": "\u0027Elixir.Saxy\u0027:encode!/2"
},
{
"name": "\u0027Elixir.Saxy\u0027:encode_to_iodata!/2"
},
{
"name": "\u0027Elixir.Saxy.Encoder\u0027:encode_to_iodata/2"
},
{
"name": "\u0027Elixir.Saxy.XML\u0027:processing_instruction/2"
}
],
"repo": "https://github.com/qcam/saxy",
"vendor": "qcam",
"versions": [
{
"lessThan": "4aeb80e2acc318f57bd7453ad2eafd59101a90e0",
"status": "affected",
"version": "7266632e9407842f28ffac254c56dc41210a5690",
"versionType": "git"
}
]
}
],
"configurations": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eThe application must serialize a document containing a processing instruction whose target or content is derived from untrusted input, by passing a \u003ccode\u003e{:processing_instruction, name, content}\u003c/code\u003e node (typically built with \u003ccode\u003eSaxy.XML.processing_instruction/2\u003c/code\u003e) to \u003ccode\u003eSaxy.encode!/2\u003c/code\u003e or \u003ccode\u003eSaxy.encode_to_iodata!/2\u003c/code\u003e. Applications that never place dynamic data in processing instructions are not affected.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "The application must serialize a document containing a processing instruction whose target or content is derived from untrusted input, by passing a `{:processing_instruction, name, content}` node (typically built with `Saxy.XML.processing_instruction/2`) to `Saxy.encode!/2` or `Saxy.encode_to_iodata!/2`. Applications that never place dynamic data in processing instructions are not affected."
}
],
"value": "The application must serialize a document containing a processing instruction whose target or content is derived from untrusted input, by passing a {:processing_instruction, name, content} node (typically built with Saxy.XML.processing_instruction/2) to Saxy.encode!/2 or Saxy.encode_to_iodata!/2. Applications that never place dynamic data in processing instructions are not affected."
}
],
"cpeApplicability": [
{
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:qcam:saxy:*:*:*:*:*:*:*:*",
"versionEndExcluding": "1.7.0",
"versionStartIncluding": "0.7.0",
"vulnerable": true
}
],
"negate": false,
"operator": "OR"
}
],
"operator": "AND"
}
],
"credits": [
{
"lang": "en",
"type": "finder",
"value": "Peter Ullrich"
},
{
"lang": "en",
"type": "reporter",
"value": "Peter Ullrich"
},
{
"lang": "en",
"type": "remediation developer",
"value": "Peter Ullrich"
},
{
"lang": "en",
"type": "remediation reviewer",
"value": "C\u1ea9m Hu\u1ef3nh"
},
{
"lang": "en",
"type": "analyst",
"value": "Jonatan M\u00e4nnchen / EEF"
},
{
"lang": "en",
"type": "coordinator",
"value": "Peter Ullrich"
}
],
"descriptions": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eSaxy\u0027s XML encoder writes the target and the content of a processing instruction into the output document verbatim, without validation or escaping. The encoder builds the construct by concatenating both fields between \u003ccode\u003e\u0026lt;?\u003c/code\u003e and \u003ccode\u003e?\u0026gt;\u003c/code\u003e, so neither field is checked against the constraints the XML specification places on it.\u003c/p\u003e\n\u003cp\u003eBecause \u003ccode\u003e?\u0026gt;\u003c/code\u003e terminates a processing instruction, a target or content value containing that sequence closes the construct at a position the attacker chooses. Everything the attacker writes after it is emitted as ordinary markup at document level, which allows arbitrary elements, attributes, and further processing instructions to be injected into the serialized document. Appending a matching \u003ccode\u003e\u0026lt;?\u003c/code\u003e keeps the encoder\u0027s own terminator well-formed, so the result still parses and the injection is silent rather than a visible corruption. The target is additionally unconstrained by the XML \u003ccode\u003eName\u003c/code\u003e production, which permits injection before the remainder of the processing instruction.\u003c/p\u003e\n\u003cp\u003eThe result is XML injection into a serialized document: the tree the application asks Saxy to encode and the tree a downstream parser reads back are no longer the same. Character data, attribute values, and comments are all escaped by the encoder, so processing instructions are the one construct that passes user bytes through untouched. Since \u003ccode\u003eSaxy.XML.processing_instruction/2\u003c/code\u003e is a documented public builder, an application inherits the flaw without misusing the API. The consequences depend on what consumes the XML: forged records in a feed or export read by another system, injected stylesheet or rendering directives, or active content where the output is served to a browser as XML or SVG.\u003c/p\u003e\n\u003cp\u003eThis issue affects saxy: from 0.7.0 before 1.7.0.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "Saxy\u0027s XML encoder writes the target and the content of a processing instruction into the output document verbatim, without validation or escaping. The encoder builds the construct by concatenating both fields between `\u003c?` and `?\u003e`, so neither field is checked against the constraints the XML specification places on it.\n\nBecause `?\u003e` terminates a processing instruction, a target or content value containing that sequence closes the construct at a position the attacker chooses. Everything the attacker writes after it is emitted as ordinary markup at document level, which allows arbitrary elements, attributes, and further processing instructions to be injected into the serialized document. Appending a matching `\u003c?` keeps the encoder\u0027s own terminator well-formed, so the result still parses and the injection is silent rather than a visible corruption. The target is additionally unconstrained by the XML `Name` production, which permits injection before the remainder of the processing instruction.\n\nThe result is XML injection into a serialized document: the tree the application asks Saxy to encode and the tree a downstream parser reads back are no longer the same. Character data, attribute values, and comments are all escaped by the encoder, so processing instructions are the one construct that passes user bytes through untouched. Since `Saxy.XML.processing_instruction/2` is a documented public builder, an application inherits the flaw without misusing the API. The consequences depend on what consumes the XML: forged records in a feed or export read by another system, injected stylesheet or rendering directives, or active content where the output is served to a browser as XML or SVG.\n\nThis issue affects saxy: from 0.7.0 before 1.7.0."
}
],
"value": "Saxy\u0027s XML encoder writes the target and the content of a processing instruction into the output document verbatim, without validation or escaping. The encoder builds the construct by concatenating both fields between \u003c? and ?\u003e, so neither field is checked against the constraints the XML specification places on it.\n\nBecause ?\u003e terminates a processing instruction, a target or content value containing that sequence closes the construct at a position the attacker chooses. Everything the attacker writes after it is emitted as ordinary markup at document level, which allows arbitrary elements, attributes, and further processing instructions to be injected into the serialized document. Appending a matching \u003c? keeps the encoder\u0027s own terminator well-formed, so the result still parses and the injection is silent rather than a visible corruption. The target is additionally unconstrained by the XML Name production, which permits injection before the remainder of the processing instruction.\n\nThe result is XML injection into a serialized document: the tree the application asks Saxy to encode and the tree a downstream parser reads back are no longer the same. Character data, attribute values, and comments are all escaped by the encoder, so processing instructions are the one construct that passes user bytes through untouched. Since Saxy.XML.processing_instruction/2 is a documented public builder, an application inherits the flaw without misusing the API. The consequences depend on what consumes the XML: forged records in a feed or export read by another system, injected stylesheet or rendering directives, or active content where the output is served to a browser as XML or SVG.\n\nThis issue affects saxy: from 0.7.0 before 1.7.0."
}
],
"impacts": [
{
"capecId": "CAPEC-250",
"descriptions": [
{
"lang": "en",
"value": "CAPEC-250 XML Injection"
}
]
}
],
"metrics": [
{
"cvssV4_0": {
"Automatable": "NOT_DEFINED",
"Recovery": "NOT_DEFINED",
"Safety": "NOT_DEFINED",
"attackComplexity": "LOW",
"attackRequirements": "PRESENT",
"attackVector": "LOCAL",
"baseScore": 2.1,
"baseSeverity": "LOW",
"privilegesRequired": "NONE",
"providerUrgency": "NOT_DEFINED",
"subAvailabilityImpact": "NONE",
"subConfidentialityImpact": "NONE",
"subIntegrityImpact": "LOW",
"userInteraction": "NONE",
"valueDensity": "NOT_DEFINED",
"vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N",
"version": "4.0",
"vulnAvailabilityImpact": "NONE",
"vulnConfidentialityImpact": "NONE",
"vulnIntegrityImpact": "LOW",
"vulnerabilityResponseEffort": "NOT_DEFINED"
},
"format": "CVSS",
"scenarios": [
{
"lang": "en",
"value": "GENERAL"
}
]
}
],
"problemTypes": [
{
"descriptions": [
{
"cweId": "CWE-91",
"description": "CWE-91 XML Injection",
"lang": "en",
"type": "CWE"
}
]
}
],
"providerMetadata": {
"dateUpdated": "2026-11-06T10:16:45.577Z",
"orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
"shortName": "EEF"
},
"references": [
{
"tags": [
"vendor-advisory",
"related"
],
"url": "https://github.com/qcam/saxy/security/advisories/GHSA-f9r9-vrxq-g566"
},
{
"name": "EEF CNA record for CVE-2026-66295",
"tags": [
"related"
],
"url": "https://cna.erlef.org/cves/CVE-2026-66295.html"
},
{
"name": "OSV record EEF-CVE-2026-66295",
"tags": [
"related"
],
"url": "https://osv.dev/vulnerability/EEF-CVE-2026-66295"
},
{
"name": "Introducing commit 7266632 in qcam/saxy",
"tags": [
"related"
],
"url": "https://github.com/qcam/saxy/commit/7266632e9407842f28ffac254c56dc41210a5690"
},
{
"name": "Fix commit 4aeb80e in qcam/saxy",
"tags": [
"patch"
],
"url": "https://github.com/qcam/saxy/commit/4aeb80e2acc318f57bd7453ad2eafd59101a90e0"
}
],
"source": {
"discovery": "EXTERNAL"
},
"title": "Processing instruction target and content emitted unescaped in Saxy encoder allows XML injection",
"workarounds": [
{
"lang": "en",
"supportingMedia": [
{
"base64": false,
"type": "text/html",
"value": "\u003cp\u003eDo not place untrusted data in processing instructions. Where a dynamic value is unavoidable, validate it before building the node: reject any content containing \u003ccode\u003e?\u0026gt;\u003c/code\u003e, and reject any target that does not match the XML \u003ccode\u003eName\u003c/code\u003e production or that equals \u003ccode\u003exml\u003c/code\u003e case-insensitively. Alternatively, carry the value in element content or an attribute instead, both of which the encoder escapes.\u003c/p\u003e"
},
{
"base64": false,
"type": "text/markdown",
"value": "Do not place untrusted data in processing instructions. Where a dynamic value is unavoidable, validate it before building the node: reject any content containing `?\u003e`, and reject any target that does not match the XML `Name` production or that equals `xml` case-insensitively. Alternatively, carry the value in element content or an attribute instead, both of which the encoder escapes."
}
],
"value": "Do not place untrusted data in processing instructions. Where a dynamic value is unavoidable, validate it before building the node: reject any content containing ?\u003e, and reject any target that does not match the XML Name production or that equals xml case-insensitively. Alternatively, carry the value in element content or an attribute instead, both of which the encoder escapes."
}
]
}
},
"cveMetadata": {
"assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
"assignerShortName": "EEF",
"cveId": "CVE-2026-66295",
"datePublished": "2026-11-06T10:16:45.577Z",
"dateReserved": "2026-07-24T14:10:01.114Z",
"dateUpdated": "2026-11-06T10:16:45.577Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
Loading…
Loading…
Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.
Experimental. This forecast is provided for visualization only and may change without notice. Do not use it for operational decisions.
Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline
Sightings and recorded dates, grouped by day · UTC
Loading timeline…
Loading…
Loading…
The MITRE ATT&CK techniques below are AI-generated suggestions, inferred from the description of the
vulnerability by the CIRCL/vulnerability-attack-technique-classification-roberta-base
model, served locally by ML-Gateway.
They have not been verified by an analyst and are provided for guidance only.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Loading…
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.