Jun 19, 2026·7 min read·11 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 directory traversal and arbitrary file read vulnerability exists in PostCSS due to an incomplete fix of CVE-2026-45623. When parsing a CSS file containing a sourceMappingURL comment with the 'from' parameter unset, path traversal and absolute path validations are bypassed, enabling attackers to read arbitrary local .map files.
CVE-2026-69152 is a high-severity Denial of Service (DoS) vulnerability in brace-expansion that allows remote, unauthenticated attackers to cause a process crash or infinite thread-blocking condition. The vulnerability stems from a complete mitigation bypass of the security checks implemented for CVE-2026-14257.
An in-depth technical analysis of CVE-2026-68945, a high-severity security vulnerability in Angular's `@angular/common/http` package. The flaw stems from an ambiguity in how query parameters are serialized to generate cache keys during Server-Side Rendering (SSR) within the `HttpTransferCache` component. By failing to encode delimiters and implicitly coercing arrays to comma-joined strings, the serialization mechanism yields identical cache keys for distinct requests, facilitating State Poisoning and Cross-Request Response Reuse.
A critical heap out-of-bounds (OOB) write vulnerability exists in the Linux kernel's IPv6 RPL (Routing Protocol for Low-Power and Lossy Networks) Segment Routing Header (SRH) processing logic. The vulnerability is located within net/ipv6/exthdrs.c, specifically in the ipv6_rpl_srh_rcv function. Under specific circumstances, when a packet containing a compressed RPL Source Routing Header is processed, segment swapping can reduce the common-prefix length, causing the recompressed header to grow. Because the kernel fails to validate available headroom on intermediate segments, a buffer underflow occurs during skb_push. This leads to an integer wrap in the MAC header offset pointer during MAC header rebuilding, causing a 14-byte out-of-bounds memory write roughly 64 KiB past the socket buffer.
CVE-2026-58263 is a high-severity Mutation Cross-Site Scripting (mXSS) vulnerability affecting Jodit Editor prior to version 4.12.28. The flaw exists in Jodit's built-in clean-html sanitizer plugin, which fails to securely parse and sanitize nested elements containing foreign namespaces like MathML and SVG. Attackers can bypass sanitization by smuggling malicious payload elements inside rawtext container tags like style inside a MathML node, leading to DOM mutation and unauthenticated arbitrary script execution in the context of the user's browser session.
Jodit Editor versions prior to 4.13.6 are vulnerable to client-side Cross-Site Scripting (XSS). The clean-html plugin's sanitization routine performs case-sensitive lookups against uppercase-only element blacklists. When processing XML-based foreign namespaces such as SVG or MathML, DOM engines preserve the lowercase format of tags. Because Jodit's denyTags check fails to normalize tag casing, malicious script blocks nested inside foreign namespace elements completely bypass validation and serialize directly into the editor output.