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

CVE-2026-86138: libxml2 Buffer Overflow Vulnerability

CVE-2026-86138 is a buffer overflow vulnerability in libxml2 affecting versions before 2.15.4. An integer overflow in xmlDictAddQString leads to heap corruption. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-86138 Overview

CVE-2026-86138 is an integer overflow vulnerability in libxml2 versions before 2.15.4. The flaw resides in the xmlDictAddQString function within dict.c, where arithmetic on dictionary pool sizes can wrap around and produce an undersized allocation. This wrap-around leads to a resultant heap-based buffer overflow when subsequent string data is written into the pool. The issue is classified as [CWE-190] Integer Overflow or Wraparound. Because libxml2 is embedded in a wide range of parsers, browsers, language runtimes, and system utilities, the vulnerability affects any local workflow that parses attacker-controlled XML using an unpatched build.

Critical Impact

Local processing of crafted XML input can trigger heap corruption in libxml2, potentially leading to memory disclosure, application crashes, or code execution in the parsing process.

Affected Products

  • GNOME libxml2 versions prior to 2.15.4
  • Applications and language bindings that statically link or embed vulnerable libxml2 builds
  • Operating system distributions shipping libxml2 before 2.15.4

Discovery Timeline

  • 2026-09-05 - CVE-2026-86138 published to the National Vulnerability Database (NVD)
  • 2026-09-08 - Last updated in NVD database

Technical Details for CVE-2026-86138

Vulnerability Analysis

The xmlDictAddQString function manages the dictionary that stores qualified XML names (prefix plus local name). When the dictionary pool needs to grow, the function computes a new pool size using multiplication and addition of caller-controlled length values. Under crafted input where the combined prefix and name lengths approach SIZE_MAX, the size calculation wraps around and returns a value that is smaller than the memory required to hold the concatenated string.

The function then calls xmlMalloc with the truncated size and writes the full prefix and local name into the undersized allocation. This produces a heap-based buffer overflow adjacent to the xmlDictStrings control structure, corrupting heap metadata and neighboring allocations.

Exploitation requires local access and a high-complexity attack path, since the attacker must produce XML content with sufficiently long qualified names and drive the dictionary allocation path deterministically. Successful exploitation can corrupt process memory, disclose sensitive data, or enable code execution within the context of the parsing application.

Root Cause

The root cause is missing overflow validation on the expressions size *= 4 and 4 * (namelen + plen + 1). Neither operation checks whether the result exceeds SIZE_MAX - sizeof(xmlDictStrings) before being passed to xmlMalloc. This is a classic [CWE-190] weakness where arithmetic on untrusted length inputs is performed in size_t without guard conditions.

Attack Vector

An attacker with local access supplies an XML document containing qualified element or attribute names crafted to force the dictionary pool to grow toward the integer overflow boundary. The vector is local, requires no privileges, and requires no user interaction, but carries high attack complexity due to the precise memory layout conditions required.

c
// Patch applied in libxml2 dict.c - xmlDictAddQString
// Source: https://github.com/GNOME/libxml2/commit/a4cba4b5b5a8c42e155ed42d2d2a44955465a2e4
            return(NULL);
        }

-       if (size == 0) size = 1000;
-       else size *= 4; /* exponential growth */
-       if (size < 4 * (namelen + plen + 1))
-           size = 4 * (namelen + plen + 1); /* just in case ! */
+       if (size == 0) {
+           size = 1000;
+       } else {
+           if (size < (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
+               size *= 4; /* exponential growth */
+           else
+               size = SIZE_MAX - sizeof(xmlDictStrings);
+       }
+       if (size / 4 < namelen + plen + 1) {
+           if ((size_t) namelen + plen + 1 <
+                   (SIZE_MAX - sizeof(xmlDictStrings)) / 4)
+               size = 4 * ((size_t) namelen + plen + 1); /* just in case ! */
+           else
+               return(NULL);
+       }
        pool = (xmlDictStringsPtr) xmlMalloc(sizeof(xmlDictStrings) + size);
        if (pool == NULL)
            return(NULL);

The fix bounds both multiplication operations against SIZE_MAX - sizeof(xmlDictStrings) and returns NULL when the requested pool size cannot be satisfied safely. See the GitHub libxml2 Commit and the GitHub libxml2 Version Comparison.

Detection Methods for CVE-2026-86138

Indicators of Compromise

  • Unexpected crashes or SIGSEGV signals in processes that link against libxml2, particularly during parsing of externally supplied XML documents.
  • Heap corruption reports from allocator instrumentation such as AddressSanitizer or glibc's MALLOC_CHECK_ when handling XML input.
  • Presence of libxml2 shared objects with version strings earlier than 2.15.4 on production hosts.

Detection Strategies

  • Inventory installed libxml2 packages and statically linked binaries, comparing reported versions against 2.15.4 across Linux distributions and container images.
  • Enable AddressSanitizer or Valgrind for QA builds that parse untrusted XML to surface heap-based buffer overflow conditions before deployment.
  • Monitor application logs and core-dump collectors for repeated failures in XML parsing components that indicate probing behavior.

Monitoring Recommendations

  • Alert on process crashes originating from libxml2 symbol frames in production telemetry.
  • Track file and network sources supplying XML into applications that embed libxml2 to identify unexpected large or malformed inputs.
  • Correlate crash telemetry with local user activity, since the attack vector requires local access.

How to Mitigate CVE-2026-86138

Immediate Actions Required

  • Upgrade libxml2 to version 2.15.4 or later on every host, container image, and build pipeline that ships the library.
  • Rebuild and redeploy applications that statically link libxml2 so the patched code path is embedded in production binaries.
  • Restrict which local users and processes may submit XML input to services that consume libxml2.

Patch Information

The fix is delivered in libxml2 2.15.4 via commit a4cba4b5b5a8c42e155ed42d2d2a44955465a2e4, which adds overflow checks to xmlDictAddQString in dict.c. Distribution maintainers typically backport the patch to supported branches, so apply vendor updates from your Linux distribution as they become available. Review the GitHub libxml2 Version Comparison for the full set of changes included in the release.

Workarounds

  • Reject or truncate XML documents containing abnormally long qualified names before they reach the parser.
  • Run XML parsing in isolated, low-privilege processes or sandboxes so heap corruption cannot escalate to the host.
  • Disable optional features that expand attacker control over dictionary growth if the consuming application exposes such tuning.
bash
# Verify installed libxml2 version and upgrade on Debian/Ubuntu
dpkg -l | grep libxml2
sudo apt-get update && sudo apt-get install --only-upgrade libxml2

# Verify installed libxml2 version and upgrade on RHEL/Fedora
rpm -q libxml2
sudo dnf upgrade libxml2

# Confirm the runtime version meets the fixed release
xmllint --version 2>&1 | head -n 1

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

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.