CVE-2026-47080 Overview
CVE-2026-47080 is an XML Injection vulnerability in the joshnuss/xml_builder Elixir library. The flaw exists in the XmlBuilder module and affects the XmlBuilder.generate/1, XmlBuilder.generate/2, and XmlBuilder.escape/1 routines in lib/xml_builder.ex. The escape/1 clause for {:cdata, data} concatenates attacker-controlled data verbatim between CDATA delimiters without neutralizing embedded ]]> sequences. An attacker who supplies input containing ]]> closes the CDATA section early, allowing arbitrary XML markup, text, or entity references to be parsed by downstream consumers. The issue affects xml_builder versions 0.0.7 through releases before 2.4.1, and is categorized under CWE-91.
Critical Impact
Attackers who control input passed to CDATA sections can inject arbitrary XML elements or entity references into generated documents, enabling content spoofing and downstream XML parser abuse.
Affected Products
- joshnuss/xml_builder Elixir library, versions 0.0.7 up to (but not including) 2.4.1
- Elixir applications consuming XmlBuilder.generate/1 and XmlBuilder.generate/2 with untrusted {:cdata, data} inputs
- Downstream XML consumers that ingest documents produced by vulnerable versions of xml_builder
Discovery Timeline
- 2026-08-21 - CVE-2026-47080 published to NVD
- 2026-08-24 - Last updated in NVD database
Technical Details for CVE-2026-47080
Vulnerability Analysis
The vulnerability originates in the escape/1 clause that handles the {:cdata, data} tuple. The function wraps data between the literal opener <![CDATA[ and closer ]]> with no transformation applied to the content. CDATA sections in XML have no internal escape mechanism, so the only correct way to embed arbitrary bytes is to split occurrences of ]]> and emit adjacent CDATA sections.
By passing input containing the sequence ]]>, an attacker terminates the CDATA context prematurely. Bytes that follow the injected terminator are interpreted as XML markup rather than character data. Downstream parsers then treat attacker-supplied strings as valid elements, attributes, text nodes, or entity references.
Exploitation can produce content spoofing in generated documents, alter downstream business logic that trusts specific XML structures, or trigger entity-based attacks if the consumer expands external entities. The impact scope depends entirely on how the produced XML is consumed.
Root Cause
The root cause is missing sanitization of the ]]> terminator sequence inside CDATA content. The vulnerable code path returns ["<![CDATA[", data, "]]>"] regardless of whether data contains the closing delimiter, violating XML CDATA construction rules.
Attack Vector
Exploitation requires the attacker to control a string passed as {:cdata, data} to XmlBuilder.generate/1 or XmlBuilder.generate/2. The advisory characterizes the attack vector as local, and no in-the-wild exploitation has been reported. There is no public proof-of-concept exploit listed in the enriched data.
// Patch diff from lib/xml_builder.ex
defp escape({:iodata, iodata}), do: iodata
defp escape({:safe, data}) when is_bitstring(data), do: data
defp escape({:safe, data}), do: to_string(data)
- defp escape({:cdata, data}), do: ["<![CDATA[", data, "]]>"]
+ defp escape({:cdata, data}),
+ do: ["<![CDATA[", String.replace(data, "]]>", "]]]]><![CDATA[>"), "]]>"]
defp escape(data) when is_binary(data),
do: data |> escape_string() |> to_string()
Source: GitHub Commit bfb1ada. The patch splits any ]]> occurrence into two adjacent CDATA sections, preserving the literal bytes while preventing premature termination.
Detection Methods for CVE-2026-47080
Indicators of Compromise
- Generated XML documents that contain unexpected elements or attributes appearing immediately after a ]]> sequence within data originally intended as CDATA content.
- Application logs showing user-controlled input containing the literal substring ]]> reaching XmlBuilder.generate/1 or XmlBuilder.generate/2.
- Downstream XML parsing errors or schema validation failures on documents produced by services using xml_builder versions earlier than 2.4.1.
Detection Strategies
- Perform dependency inventory across Elixir and Erlang projects to identify any use of xml_builder at versions 0.0.7 through 2.4.0.
- Add static analysis rules that flag calls to XmlBuilder.generate where the {:cdata, ...} tuple carries data derived from untrusted sources.
- Implement input-validation tests that submit payloads containing ]]> and verify the resulting XML preserves CDATA integrity.
Monitoring Recommendations
- Monitor request bodies and API parameters for the literal ]]> sequence in fields that will be serialized to XML.
- Alert on XML documents produced by internal services that fail downstream schema validation after deployment of xml_builder-based components.
- Track mix.lock and mix.exs changes in source control to detect regressions to vulnerable versions of xml_builder.
How to Mitigate CVE-2026-47080
Immediate Actions Required
- Upgrade xml_builder to version 2.4.1 or later in all affected Elixir projects.
- Audit code paths that pass externally sourced data to {:cdata, data} tuples and add input validation where feasible.
- Rebuild and redeploy any services that produce XML consumed by external partners or downstream parsers.
Patch Information
The fix is committed in GitHub Commit bfb1ada and documented in the GitHub Security Advisory GHSA-67r9-hmxw-h595. The patch replaces every occurrence of ]]> in CDATA content with ]]]]><![CDATA[>, splitting the sequence across adjacent CDATA sections. Additional metadata is available in the CNA advisory for CVE-2026-47080 and the OSV record EEF-CVE-2026-47080.
Workarounds
- Before upgrading, wrap CDATA writes in a helper that manually splits ]]> into adjacent CDATA sections using String.replace(data, "]]>", "]]]]><![CDATA[>").
- Reject or strip inputs containing ]]> at the application boundary when the field will be emitted inside a CDATA section.
- Prefer non-CDATA encodings for untrusted text by passing plain strings to XmlBuilder so that character-entity escaping is applied.
# Update the dependency in mix.exs and refresh the lockfile
# {:xml_builder, "~> 2.4.1"}
mix deps.update xml_builder
mix deps.get
mix compile --force
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

