Jun 19, 2026·7 min read·2 visits
A Use-After-Free vulnerability in Nokogiri's CRuby C-extension engine allows memory corruption or application crashes when XInclude is run on previously traversed DOM structures. The issue is resolved in version 1.19.4 by performing XInclude substitutions on a defensive copy.
Nokogiri is a popular Ruby gem used for parsing XML and HTML documents. A Use-After-Free (UAF) vulnerability exists in its CRuby implementation during XInclude processing. When an application traverses an XML document and exposes nodes to Ruby before calling `do_xinclude`, the underlying C library `libxml2` can free these structures in-place. This leaves active Ruby objects holding pointers to freed memory, leading to potential segmentation faults, memory corruption, or information disclosure.
The library Nokogiri is a widely used XML and HTML processing library for the Ruby programming language. In its CRuby implementation, Nokogiri relies heavily on native C extensions wrapping the libxml2 library. This architecture allows Nokogiri to achieve high-performance parsing, schema validation, and XPath querying. However, managing the lifecycle of C-level memory structures alongside Ruby garbage-collected objects requires precise pointer tracking and reference counting.
GHSA-WFPW-MMFH-QQ69 identifies a Use-After-Free (UAF) vulnerability inside the XML node-level XInclude processing engine, specifically within the Nokogiri::XML::Node#do_xinclude method. The vulnerability arises because of a misalignment between the lifetime of C memory structures managed by libxml2 and the Ruby objects wrapping them. When XML documents containing XML Inclusions (XInclude) elements are processed, the underlying engine can free structural nodes without notifying the Ruby-level garbage collector.
The attack surface is exposed when an application processes untrusted XML documents, parses them into a Document Object Model (DOM), traverses the DOM to expose specific subtrees to the Ruby runtime, and subsequently triggers manual XInclude processing. Because this API call sequence is uncommon, the severity is classified as low. Nevertheless, if triggered, the flaw leads to memory corruption, potential information disclosure, or application crash.
To understand the root cause, one must examine how Nokogiri bridges Ruby objects and C structures. When Nokogiri processes an XML document, it maps C structures like xmlNode and xmlNs to Ruby classes such as Nokogiri::XML::Node and Nokogiri::XML::Namespace. Nokogiri maintains an internal registry to track these allocations. This registry ensures that as long as a Ruby object references a node, the underlying C structure is not freed, and conversely, that dead Ruby wrappers do not leak C memory.
The core of the vulnerability lies within the interaction between Nokogiri::XML::Node#do_xinclude and the libxml2 function xmlXIncludeProcessNode. When executing XInclude processing, libxml2 parses external targets and merges them into the current document. If the document contains an <xi:include> tag, libxml2 replaces this element with the target contents. Consequently, the original <xi:include> node, its child nodes (such as <xi:fallback>), and its local namespaces are freed within the C library heap.
If the Ruby application has already traversed into the subtree of the <xi:include> element before calling do_xinclude, the Ruby interpreter has already instantiated wrapper objects pointing directly to those internal C nodes. Since libxml2 executes the free operation directly inside the C layer, Nokogiri's reference-tracking system is bypassed. The live Ruby objects are left holding pointers to deallocated heap locations, representing a classic Use-After-Free condition.
Subsequent operations on these stale Ruby wrapper objects cause the virtual machine to dereference the invalid pointers. If the memory remains unallocated, the application typically terminates with a segmentation fault. If the memory has been reallocated by other processes or structures within the Ruby allocator, the application may read arbitrary heap memory or write to active structures, resulting in data exposure or remote code execution.
The vulnerability manifests when invoking Nokogiri::XML::Node#do_xinclude on a document that has already been traversed. In older versions of Nokogiri, this method invoked the underlying C library directly on the active DOM tree. The C extension executed the processing in-place, modifying the live document structure and freeing nodes that were still bound to active Ruby-level variables.
To prevent this in-place modification and subsequent pointer invalidation, the maintainers modified the implementation in version 1.19.4. The updated code performs the XInclude processing on a duplicate, defensive copy of the document or nodes. Below is a conceptual representation of the modification introduced in the remediation:
# Vulnerable implementation concept
def do_xinclude
# Modifies the live C structure directly in-place
# This frees nodes that Ruby objects may still reference
_native_do_xinclude(self)
end
# Patched implementation concept in 1.19.4
def do_xinclude
# Perform XInclude processing on a duplicate of the node/document
# This protects the active, traversed tree from being modified in-place
duplicate_node = self.dup
_native_do_xinclude(duplicate_node)
# Replace the children of the current node safely with the processed duplicate
self.children = duplicate_node.children
self
endBy working on a duplicate tree, any node destruction occurs on elements that have never been exposed to the Ruby runtime. The active DOM tree remains intact, and any previously referenced Ruby nodes continue to point to valid memory addresses. This defense-in-depth approach completely isolates the side-effects of the destructive C-level operations from the user-facing Ruby variables.
Exploiting this Use-After-Free vulnerability requires a specific, multi-step API interaction. The attacker must find an application endpoint that accepts untrusted XML documents, parses them, traverses into an XInclude subtree to instantiate Ruby objects, and then explicitly executes XInclude processing on the node or document.
The following block illustrates the conceptual flow required to trigger the vulnerability:
To reproduce the memory corruption, an XML document must contain an <xi:include> element and an <xi:fallback> element. The application must parse the input without the immediate XInclude option, run a search or traversal such as doc.at_xpath("//xi:fallback") to create a live Ruby object, and then call doc.do_xinclude. Calling any method on the retrieved fallback node after this point causes the Ruby interpreter to access freed memory.
Because this sequence of API calls is highly uncommon, the exploitability of this vulnerability in real-world scenarios is extremely limited. Applications typically either process XIncludes at parse time or do not process them at all. Furthermore, there are no known public exploits or automated exploitation payloads targeting this vulnerability in the wild, indicating that the threat remains theoretical.
The impact of a Use-After-Free vulnerability is heavily dependent on the memory layout and the actions performed on the stale pointers. At a minimum, accessing the freed memory results in an immediate segmentation fault, leading to a Denial of Service (DoS) of the application process. In multi-threaded application servers, a segmentation fault typically terminates the worker process, impacting availability.
In highly specific environments, an attacker could attempt to manipulate the heap layout to achieve arbitrary code execution. By triggering the allocation of attacker-controlled structures immediately after the XInclude node is freed, the stale pointer could be made to point to controlled payload data. If the application then invokes a virtual method or dereferences a callback pointer on the stale Ruby object, control flow could be hijacked.
However, executing such heap grooming techniques within the Ruby virtual machine is highly complex due to the asynchronous nature of the Ruby garbage collector and the internal allocator designs of CRuby. The vulnerability is thus considered a low-severity risk. Since JRuby does not use the C-based libxml2 wrapper, but instead relies on native Java parsers, systems running on the JRuby runtime are completely immune to this vulnerability.
The primary remediation path is upgrading the Nokogiri gem to version 1.19.4 or higher. This update changes the behavior of #do_xinclude to use defensive copying, shielding active Ruby references from the underlying memory modifications. If an immediate upgrade is not feasible, developers should inspect their codebases for instances of explicit #do_xinclude invocations.
Where upgrading is delayed, developers can mitigate the risk by modifying the XML parsing configuration. Rather than calling #do_xinclude manually on an already parsed and traversed document, applications should enable XInclude processing at the initial parsing stage. This approach processes the XML inclusions before any Ruby objects are created, preventing the lifetime misalignment entirely.
# Safe pattern for older Nokogiri versions:
# Enable XInclude processing during parsing
doc = Nokogiri::XML(xml_data) do |config|
config.xinclude
endAdditionally, static analysis can be utilized to locate potential vulnerabilities. Security teams should run software composition analysis (SCA) tools to identify vulnerable versions of the Nokogiri gem within their dependency graphs. Security audits should focus on ensuring that untrusted XML input is sanitized and that unnecessary parsing options, such as external entity resolution and XIncludes, are disabled unless explicitly required.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
nokogiri sparklemotion | < 1.19.4 | 1.19.4 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-416 |
| Attack Vector | Network (with local programmatic triggers) |
| CVSS Score | 4.8 (Medium/Low) |
| Impact | Memory Corruption / Denial of Service |
| Exploit Status | None (No public exploit) |
| KEV Status | Not Listed |
A critical missing authorization vulnerability exists in the API Pages Controller of Alchemy CMS. An unauthenticated remote attacker can exploit the 'nested' action to retrieve the entire nested page tree. Furthermore, by appending the query parameter '?elements=true', the attacker can extract sensitive content from draft, unpublished, and restricted pages, bypassing all access controls.
A use-after-free (UAF) vulnerability exists in the CRuby native extension of the Nokogiri gem when updating XML attribute values. If child nodes of an XML attribute are wrapped by Ruby objects prior to setting the attribute's value, the underlying C memory structures are freed while the Ruby wrapper retains a dangling pointer. This results in memory corruption, invalid pointer dereferences, and application crashes during execution or garbage collection.
A client-side Stored Cross-Site Scripting (XSS) vulnerability exists in the JupyterLab Extension Manager. This vulnerability allows an attacker to register a malicious package on the Python Package Index (PyPI) with a crafted metadata homepage URL using the 'javascript:' pseudo-protocol. When a JupyterLab user opens the Extension Manager and clicks the extension name, the browser executes arbitrary JavaScript code within the context of the JupyterLab origin. This can lead to the theft of active workspace documents, credentials, and API tokens. The issue affects all versions of JupyterLab prior to version 4.5.9.
An arbitrary Remote Code Execution (RCE) vulnerability exists in ouroboros-ai due to an incomplete fix for CVE-2026-47211. Ouroboros automatically loads environment configurations from local .env files located in the current working directory (CWD) of cloned repositories. Although a denylist (_UNTRUSTED_ENV_DENYLIST) was introduced in version 0.39.0 to filter out execution-routing environment variables, multiple critical configuration variables were omitted, enabling complete sandbox bypass and arbitrary system command execution.
An OS command injection vulnerability (CWE-78) exists in agentic-flow versions 2.0.13 and prior. The package's Model Context Protocol (MCP) server tools directly interpolate user-controlled parameters into shell command strings executed via child_process.execSync without validation. If an AI agent processes untrusted external input and forwards it as parameters to any affected tool, an attacker can break out of the shell argument quotes and execute arbitrary OS commands on the host machine.
A high-severity denial of service vulnerability in the undici WebSocket client (CVE-2026-12151) arises from uncontrolled memory consumption. Although undici validates individual fragment sizes against a cumulative payload limit, it fails to cap the total number of frames in a single message stream. This allows a rogue or compromised WebSocket server to send an infinite sequence of small or empty continuation frames, causing unbounded memory allocation and eventual heap exhaustion on the client process.