Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-47079

CVE-2026-47079: XML Builder XSS Vulnerability

CVE-2026-47079 is a cross-site scripting flaw in joshnuss xml_builder that allows attackers to inject malicious markup by exploiting improper entity encoding. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-47079 Overview

CVE-2026-47079 is an inappropriate output encoding vulnerability in the joshnuss xml_builder library for Elixir. The flaw resides in the XmlBuilder module inside lib/xml_builder.ex and affects the XmlBuilder.generate/1, XmlBuilder.generate/2, XmlBuilder.escape_string/1, and XmlBuilder.escape_entity/1 routines. The library fails to escape literal & characters when they precede entity-like tokens such as lt;, gt;, amp;, quot;, or apos;. Attackers can leverage this encoding gap to smuggle markup through upstream filters and achieve content spoofing or cross-site scripting in downstream consumers that render the produced XML.

Critical Impact

Attacker-supplied input like <script> is emitted verbatim into serialized XML, allowing markup injection into HTML, SVG, or RSS/Atom consumers that decode entity sequences during parsing.

Affected Products

  • joshnuss/xml_builder (Elixir library) versions 0.0.6 through 2.4.0
  • Downstream Elixir applications generating XML, RSS, Atom, or SVG output via XmlBuilder.generate/1 or XmlBuilder.generate/2
  • Any consumer that parses the produced XML and renders text content in a markup-sensitive context

Discovery Timeline

  • 2026-08-21 - CVE-2026-47079 published to NVD
  • 2026-08-24 - Last updated in NVD database

Technical Details for CVE-2026-47079

Vulnerability Analysis

The vulnerability is classified as Inappropriate Encoding for Output Context [CWE-838] and manifests as a stored cross-site scripting and content spoofing primitive. XmlBuilder.generate/1 processes text and attribute values through escape_string/1, which delegates any literal & character to escape_entity/1. That helper checks whether the following bytes form a recognized entity token. When they do, escape_entity/1 emits the fully decoded entity (for example <) rather than treating the raw & as data that must be escaped to &. Downstream XML parsers then decode <script> into literal <script> markup, defeating any upstream filter that only blocked raw < and > characters.

Root Cause

The root cause is a serialization ambiguity between raw text and pre-encoded entities. The library treats a literal & followed by an entity-like suffix as though the caller intended to pass an already-encoded entity through unchanged. XML serializers must always escape & to & in text and attribute contexts, regardless of what follows. The optimistic entity-passthrough in escape_entity/1 breaks that invariant and produces non-round-trippable output.

Attack Vector

An attacker submits input such as <script>alert(1)</script> into any field that eventually flows into XmlBuilder.generate/1 as element text or an attribute value. The library emits the payload verbatim into the XML document. When a feed reader, browser, or SVG renderer parses the document, entity decoding restores the literal <script> tags, executing the injected markup in the victim's context. Both element text and attribute values are affected.

elixir
// Security patch in lib/xml_builder.ex - Fix escaping of ampersand character
     do: data |> to_string() |> escape_string() |> to_string()
 
   defp escape_string(""), do: ""
-  defp escape_string(<<"&"::utf8, rest::binary>>), do: escape_entity(rest)
+  defp escape_string(<<"&"::utf8, rest::binary>>), do: ["&" | escape_string(rest)]
   defp escape_string(<<"<"::utf8, rest::binary>>), do: ["<" | escape_string(rest)]
   defp escape_string(<<">"::utf8, rest::binary>>), do: [">" | escape_string(rest)]
   defp escape_string(<<"\""::utf8, rest::binary>>), do: [""" | escape_string(rest)]
   defp escape_string(<<"'"::utf8, rest::binary>>), do: ["'" | escape_string(rest)]
   defp escape_string(<<c::utf8, rest::binary>>), do: [c | escape_string(rest)]
 
-  defp escape_entity(<<"amp;"::utf8, rest::binary>>), do: ["&" | escape_string(rest)]
-  defp escape_entity(<<"lt;"::utf8, rest::binary>>), do: ["<" | escape_string(rest)]
-  defp escape_entity(<<"gt;"::utf8, rest::binary>>), do: [">" | escape_string(rest)]
-  defp escape_entity(<<"quot;"::utf8, rest::binary>>), do: [""" | escape_string(rest)]
-  defp escape_entity(<<"apos;"::utf8, rest::binary>>), do: ["'" | escape_string(rest)]
-  defp escape_entity(rest), do: ["&" | escape_string(rest)]

Source: GitHub Commit c3390e20 — the patch removes the entity-passthrough helper and unconditionally escapes & to &.

Detection Methods for CVE-2026-47079

Indicators of Compromise

  • XML, RSS, or Atom documents produced by an application dependency chain including xml_builder where text or attribute nodes contain literal <, >, &, ", or ' sequences instead of &lt;.
  • Log entries showing user-controlled input containing sequences like <script> or " onerror= reaching XML serialization routines.
  • Downstream renderers reporting unexpected script execution, iframes, or spoofed content in fields sourced from XmlBuilder output.

Detection Strategies

  • Inventory Elixir applications for xml_builder versions between 0.0.6 and 2.4.0 using mix deps or SBOM tooling.
  • Add differential tests that assert XmlBuilder.generate/1 emits &lt; when the input contains the literal string <.
  • Fuzz XML output endpoints with payloads such as <, >, &, and " and inspect the serialized output for unescaped ampersands.

Monitoring Recommendations

  • Monitor web application firewall and reverse proxy logs for requests containing entity-encoded XSS payloads directed at endpoints that emit XML content types.
  • Alert on client-side content security policy violations originating from RSS, Atom, or SVG resources generated by affected services.
  • Track dependency update events in CI/CD pipelines to confirm xml_builder is pinned to a fixed version.

How to Mitigate CVE-2026-47079

Immediate Actions Required

  • Upgrade xml_builder to version 2.4.1 or later in every Elixir project that depends on it, directly or transitively.
  • Audit all call sites of XmlBuilder.generate/1 and XmlBuilder.generate/2 that handle untrusted input and re-serialize any cached XML output produced by vulnerable versions.
  • Review downstream consumers of the generated XML for evidence of injected markup and invalidate cached feed content if necessary.

Patch Information

The fix is committed in GitHub commit c3390e20 and released in xml_builder2.4.1. See the GitHub Security Advisory GHSA-5hjx-8g53-cmvm, the Erlang Ecosystem Foundation CNA advisory, and the OSV entry EEF-CVE-2026-47079 for authoritative details.

Workarounds

  • Pre-encode user input by replacing every literal & with & before passing values to XmlBuilder.generate/1 when patching is not immediately possible.
  • Apply strict output-context escaping at the downstream renderer, for example HTML-escaping RSS or Atom content before rendering in a browser.
  • Enforce a Content Security Policy on any consumer that renders the generated XML in an HTML context to limit the impact of injected scripts.
bash
# Update the dependency in mix.exs
# {:xml_builder, "~> 2.4.1"}
mix deps.update xml_builder
mix deps.get
mix compile

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.