{"id":"CVE-2026-66295","kind":"vulnerability","aliases":["CVE-2026-66295"],"related":[],"title":"Saxy: XML encoder lets processing instructions inject arbitrary markup","description":"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.\n\nBecause ?> 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.\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.","summary":"Saxy's XML encoder writes processing instruction targets and content into output without validation or escaping, so a value containing ?> closes the instruction early. An attacker can then inject arbitrary elements and directives into serialized XML that downstream parsers read as trusted.","severity":"low","cvss":2.1,"epss":null,"exploited":false,"exploited_at":null,"products":[],"ecosystems":[],"tags":["elixir","package","saxy","xml"],"not_affected_if":["no-user-input-in-processing-instructions","saxy-1.7.0-or-later"],"how_to_check":"- Check the saxy version in `mix.lock` or `mix deps | grep saxy`\n- Search the code for `Saxy.XML.processing_instruction` or `processing_instruction(` calls that take user-supplied values","fix":"- `saxy` `1.7.0` (fixed from 0.7.0 up to, but not including, 1.7.0)","status":"open","published_at":"2026-11-06T11:17:16+00:00","first_seen_at":"2026-11-06T11:41:29+00:00","triaged_at":"2026-11-06T11:43:57+00:00","updated_at":"2026-11-06T11:43:57+00:00","category":"package","confidence":0.7,"triage":{"at":"2026-11-06T11:43:57Z","model":"claude-haiku-5-5","output":{"fix":"- `saxy` `1.7.0` (fixed from 0.7.0 up to, but not including, 1.7.0)","reach":"unknown","title":"Saxy: XML encoder lets processing instructions inject arbitrary markup","impact":"medium","summary":"Saxy's XML encoder writes processing instruction targets and content into output without validation or escaping, so a value containing ?> closes the instruction early. An attacker can then inject arbitrary elements and directives into serialized XML that downstream parsers read as trusted.","audience":"developers","category":"package","nicknames":[],"who_cares":["elixir","saxy","xml"],"confidence":0.7,"fix_status":"available","needs_auth":"unknown","worst_case":"forged XML records and active markup injected into downstream documents","analyst_note":"","how_to_check":"- Check the saxy version in `mix.lock` or `mix deps | grep saxy`\n- Search the code for `Saxy.XML.processing_instruction` or `processing_instruction(` calls that take user-supplied values","plain_action":"","needs_analyst":false,"not_affected_if":["no-user-input-in-processing-instructions","saxy-1.7.0-or-later"],"who_is_affected":"Applications that build XML with Saxy and pass user-controlled values into processing instructions via Saxy.XML.processing_instruction/2 are exposed. Output consumed by another system, such as a feed, export or browser-rendered XML or SVG, is where injected markup matters. Projects that never put untrusted data into processing instructions can skip it.","user_interaction":"no","needs_special_setup":"no","severity_if_unknown":"low"},"cost_usd":0.000751,"input_tokens":4663,"output_tokens":570,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-2026':11A,14A '-66295':12A,15A '0.7.0':325C '1.7.0':327C 'activ':306C 'addit':192C 'affect':322C 'allow':147C 'anoth':298C 'api':280C 'append':162C 'applic':221C,273C 'arbitrari':8A,49B,148C 'ask':222C 'attack':45B,130C,134C 'attribut':150C,241C 'back':233C 'browser':315C 'build':87C 'builder':271C 'byte':261C 'charact':239C 'check':100C 'choos':131C 'close':40B,123C 'comment':244C 'concaten':91C 'consequ':282C 'constraint':103C 'construct':89C,125C,257C 'consum':286C 'contain':39B,120C 'content':29B,71C,118C,307C 'corrupt':188C 'cve':10A,13A 'data':240C 'depend':283C 'direct':52B,304C 'document':79C,144C,161C,217C,269C 'downstream':57B,230C 'earli':43B 'element':50B,149C 'elixir':16B 'emit':139C 'encod':3A,23B,65C,86C,167C,225C,250C 'escap':35B,84C,247C 'everyth':132C 'export':295C 'feed':293C 'field':93C,98C 'flaw':276C 'forg':289C 'form':173C 'inherit':274C 'inject':7A,48B,157C,181C,201C,213C,300C 'instruct':6A,26B,42B,75C,114C,154C,208C,253C 'instruction/2':266C 'issu':321C 'keep':165C 'let':4A 'level':145C 'longer':236C 'markup':9A,142C 'match':164C 'misus':278C 'name':197C 'neither':97C 'one':256C 'ordinari':141C 'output':31B,78C,310C 'packag':17B 'pars':178C 'parser':58B,231C 'pass':259C 'permit':200C 'place':107C 'posit':128C 'process':5A,25B,74C,113C,153C,207C,252C 'product':198C 'public':270C 'rather':184C 'read':59B,232C,296C 'record':290C 'remaind':204C 'render':303C 'result':176C,210C 'saxi':1A,18B,20B,62C,223C,323C 'saxy.xml.processing':265C 'sequenc':122C 'serial':54B,160C,216C 'serv':312C 'silent':183C 'sinc':264C 'specif':106C 'still':177C 'stylesheet':301C 'svg':319C 'system':299C 'target':27B,68C,116C,190C 'termin':111C,170C 'tree':219C,228C 'trust':61B 'unconstrain':193C 'untouch':263C 'user':260C 'valid':33B,82C 'valu':38B,119C,242C 'verbatim':80C 'visibl':187C 'well':172C 'well-form':171C 'without':32B,81C,277C 'write':24B,66C,135C 'xml':2A,19B,22B,55B,64C,105C,196C,212C,288C,317C","nicknames":[],"mitigations":[],"who_affected":"Applications that build XML with Saxy and pass user-controlled values into processing instructions via Saxy.XML.processing_instruction/2 are exposed. Output consumed by another system, such as a feed, export or browser-rendered XML or SVG, is where injected markup matters. Projects that never put untrusted data into processing instructions can skip it.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":[],"ptokens":[],"labels":["elixir","low","package","saxy","xml"],"campaign_type":null,"search_a":"'-2026':11A,14A '-66295':12A,15A 'arbitrari':8A 'cve':10A,13A 'encod':3A 'inject':7A 'instruct':6A 'let':4A 'markup':9A 'process':5A 'saxi':1A 'xml':2A","search_b":"'arbitrari':49B 'attack':45B 'close':40B 'contain':39B 'content':29B 'direct':52B 'downstream':57B 'earli':43B 'element':50B 'elixir':16B 'encod':23B 'escap':35B 'inject':48B 'instruct':26B,42B 'output':31B 'packag':17B 'parser':58B 'process':25B 'read':59B 'saxi':18B,20B 'serial':54B 'target':27B 'trust':61B 'valid':33B 'valu':38B 'without':32B 'write':24B 'xml':19B,22B,55B","search_c":"'0.7.0':325C '1.7.0':327C 'activ':306C 'addit':192C 'affect':322C 'allow':147C 'anoth':298C 'api':280C 'append':162C 'applic':221C,273C 'arbitrari':148C 'ask':222C 'attack':130C,134C 'attribut':150C,241C 'back':233C 'browser':315C 'build':87C 'builder':271C 'byte':261C 'charact':239C 'check':100C 'choos':131C 'close':123C 'comment':244C 'concaten':91C 'consequ':282C 'constraint':103C 'construct':89C,125C,257C 'consum':286C 'contain':120C 'content':71C,118C,307C 'corrupt':188C 'data':240C 'depend':283C 'direct':304C 'document':79C,144C,161C,217C,269C 'downstream':230C 'element':149C 'emit':139C 'encod':65C,86C,167C,225C,250C 'escap':84C,247C 'everyth':132C 'export':295C 'feed':293C 'field':93C,98C 'flaw':276C 'forg':289C 'form':173C 'inherit':274C 'inject':157C,181C,201C,213C,300C 'instruct':75C,114C,154C,208C,253C 'instruction/2':266C 'issu':321C 'keep':165C 'level':145C 'longer':236C 'markup':142C 'match':164C 'misus':278C 'name':197C 'neither':97C 'one':256C 'ordinari':141C 'output':78C,310C 'pars':178C 'parser':231C 'pass':259C 'permit':200C 'place':107C 'posit':128C 'process':74C,113C,153C,207C,252C 'product':198C 'public':270C 'rather':184C 'read':232C,296C 'record':290C 'remaind':204C 'render':303C 'result':176C,210C 'saxi':62C,223C,323C 'saxy.xml.processing':265C 'sequenc':122C 'serial':160C,216C 'serv':312C 'silent':183C 'sinc':264C 'specif':106C 'still':177C 'stylesheet':301C 'svg':319C 'system':299C 'target':68C,116C,190C 'termin':111C,170C 'tree':219C,228C 'unconstrain':193C 'untouch':263C 'user':260C 'valid':82C 'valu':119C,242C 'verbatim':80C 'visibl':187C 'well':172C 'well-form':171C 'without':81C,277C 'write':66C,135C 'xml':64C,105C,196C,212C,288C,317C","first_public_at":"2026-11-06T11:17:16+00:00","kev":null,"cvss_vector":"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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","cvss_by":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","poc_count":0,"sources":[{"source":"nvd","external_id":"CVE-2026-66295","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-66295","severity":null,"published_at":"2026-11-06T11:17:16+00:00","modified_at":"2026-11-06T11:17:16+00:00","first_seen_at":"2026-11-06T11:41:29+00:00","fetched_at":"2026-11-06T11:41:29+00:00","note":null}],"documents":[{"id":85910,"url":"https://github.com/qcam/saxy/commit/4aeb80e2acc318f57bd7453ad2eafd59101a90e0","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":85905,"url":"https://github.com/qcam/saxy/commit/7266632e9407842f28ffac254c56dc41210a5690","title":"Patch: github.com","kind":"other","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":85912,"url":"https://github.com/qcam/saxy/security/advisories/GHSA-f9r9-vrxq-g566","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Vendor advisory: github.com"}],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}