CVE-2025-24855 - Exploiting Use-After-Free in libxslt’s numbers.c (Before 1.1.43) – A Hands-On Guide

---

Introduction: What is CVE-2025-24855?

CVE-2025-24855 uncovers a dangerous use-after-free vulnerability in libxslt (prior to version 1.1.43). The issue lurks in numbers.c, where, during certain XPath operations, the context node is altered, but not safely restored after complex, nested evaluations.

If exploited, this bug could lead to crashes or even code execution when processing specially crafted XSLT stylesheets. Let’s break down how this bug works, why it’s a big deal, and how an attacker might take advantage of it.

What is libxslt?

libxslt is a widely-used C library for transforming XML documents using XSLT (Extensible Stylesheet Language Transformations). Hundreds of programs (including web servers and office suites) ship it in their dependency tree.

The core problem lies in nested XPath evaluations within numbers.c. Here’s what happens

- Functions like xsltNumberFormatGetValue, xsltEvalXPathPredicate, xsltEvalXPathStringNs, and xsltComputeSortResultInternal may change the XPath context node (think: “where in the XML tree are you?”) as they run.
- However, these changes are NOT always reverted. If an XPath expression triggers freeing memory (i.e., marking a node as deleted), later code may use a freed node reference.

This is a classic use-after-free bug. It's often a stepping stone to denial of service (crashing), information leaks, or arbitrary code execution—depending on follow-up codepaths and memory layout.

Code Walkthrough

Here’s an illustrative (simplified) snippet based on real code paths, zooming into the heart of the problem:

// numbers.c - simplified logic
xmlNodePtr oldNode = ctxt->node;
ctxt->node = someOtherNode;

xmlXPathObjectPtr res = xsltEvalXPathPredicate(ctxt, pred);
// ... inside xsltEvalXPathPredicate, ctxt->node may be changed/freed

ctxt->node = oldNode; // But what if oldNode is now freed?

After calling xsltEvalXPathPredicate, there’s a risk that oldNode is already freed, but we restore it back into the context. The next function using ctxt->node could then try to read memory that no longer belongs to the program, leading to weird crashes or, with enough luck, code execution.

Exploit Scenario (PoC)

An attacker could write a custom XML stylesheet that performs recursive or nested evaluations, triggering the context node to point to freed memory. Here’s a basic (conceptual) XSLT example:

<xsl:template match="/">
    <xsl:number count="*[
        (preceding-sibling::* and generate-id() = generate-id(preceding-sibling::*[1]))
        or
        (following-sibling::* and generate-id() = generate-id(following-sibling::*[1]))
    ]"/>
</xsl:template>

Such constructs spur nested XPath calls, moving the context node often and using complex predicates. With heap grooming (forcing certain memory layouts), a motivated attacker could turn this into something worse—like code execution.

Using libxslt before 1.1.43.

- Relying on XSLT stylesheets containing nested or recursive XPath predicates during number formatting or sorting.

Run your processing under tools like AddressSanitizer (ASan) to catch use-after-free bugs.

Mitigation (How to Fix)

*Upgrade libxslt to version 1.1.43 or higher.*
The maintainers fixed the issue by being more careful with the context node—saving/restoring and validating its ownership before reuse.

- Official CVE Record – CVE-2025-24855
- libxslt Release Notes / Changelog
- libxslt Source Code
- Use-After-Free Wiki Explanation

Final Thoughts

Even mature XML libraries like libxslt can suffer from subtle memory management bugs, especially in deeply-nested or contrived workflows. If you process untrusted XML/XSLT, upgrade now, and consider sandboxing or limiting capabilities.

Timeline

Published on: 03/14/2025 02:15:15 UTC