CVE-2026-91765

Uncontrolled Recursion
Affects
PHP
in
PHP
No items found.
Versions
<8.2.34, >=8.3.0 <8.3.35, >=8.4.0 <8.4.26, >=8.5.0 <8.5.11

Patch Available.

Exclamation circle icon
Patch Available

This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.

Overview

PHP is a general-purpose scripting language used mostly for web development. It runs behind web servers through server APIs such as Apache mod_php and PHP-FPM, and powers content management systems and frameworks such as WordPress, Drupal, Moodle and Laravel. Its soap extension implements SOAP clients and servers through the SoapClient and SoapServer classes, parsing SOAP messages and WSDL files with libxml2 and decoding them into PHP values.

A Denial of Service (DoS) vulnerability (CVE-2026-91765) has been identified in the XML handling of PHP's soap extension, which allows an unauthenticated attacker who can send a SOAP message to a SoapServer endpoint, or a malicious server that answers a SoapClient, to exhaust the C stack with a deeply nested document and crash the PHP process. PHP tracks this issue as GHSA-rgrp-mwpx-f6rm.

Per MITRE CWE-674: The product does not properly control the amount of recursion that takes place, consuming excessive resources, such as allocated memory or the program stack.

This issue affects PHP 8.2 before 8.2.34, PHP 8.3 before 8.3.35, PHP 8.4 before 8.4.26 and PHP 8.5 before 8.5.11, as well as all releases of the End-of-Life PHP 5.6 through 8.1 release lines.

Details

Module Info

Vulnerability Info

This High-severity vulnerability is found in the soap extension of PHP 8.2 before 8.2.34, 8.3 before 8.3.35, 8.4 before 8.4.26 and 8.5 before 8.5.11, and in the End-of-Life PHP 5.6 through 8.1 release lines, which never received the upstream fix. The PHP project scores it 7.5 under CVSS 3.1 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).

The extension parses SOAP messages and WSDL files with libxml2's XML_PARSE_HUGE option, which with libxml2 versions older than 2.13 removes libxml2's own nesting limit. It then walks the resulting tree with recursive C functions: cleanup_xml_node(), which strips insignificant nodes from loaded WSDL files, the lookup that resolves href references between parts of a message, and the decoder that turns the message into PHP values. Each of them calls itself once per nesting level. In PHP 7.4.33 the href lookup reads:

xmlNodePtr get_node_with_attribute_recursive_ex(xmlNodePtr node, char *name, char *name_ns, char *attribute, char *value, char *attr_ns)
{
    while (node != NULL) {
        if (node_is_equal_ex(node, name, name_ns)) {
            xmlAttrPtr attr = get_attribute_ex(node->properties, attribute, attr_ns);
            if (attr != NULL && strcmp((char*)attr->children->content, value) == 0) {
                return node;
            }
        }
        if (node->children != NULL) {
            xmlNodePtr tmp = get_node_with_attribute_recursive_ex(node->children, name, name_ns, attribute, value, attr_ns);
            if (tmp) {
                return tmp;
            }
        }
        node = node->next;
    }
    return NULL;
} 

None of these functions limits its depth, so a message with tens of thousands of nested elements, or a long or cyclic chain of href references, needs more stack frames than the C stack can hold. The process then crashes, typically with a segmentation fault. On PHP-FPM or Apache this kills the worker handling the request, and repeated requests can keep a SOAP service unavailable.

Exploitation needs an application that uses the soap extension. Any SoapServer endpoint that handles requests from an attacker is exposed without authentication, since the crash happens while PHP parses and decodes the request, before application code runs. A SoapClient is exposed when it reads a response or WSDL file from a malicious or compromised server. Any SAPI is affected. Servers that do not build or load ext/soap are not affected.

The fix, by Alexandre Daubois, makes the cleanup and the href lookup iterative, refuses documents nested deeper than 2048 levels when PHP is built against libxml2 older than 2.13, and stops decoding beyond 4096 levels with an error instead of crashing. The iterative lookup reads:

if (node->children != NULL &&
    node->type != XML_ENTITY_REF_NODE &&
    node->type != XML_DTD_NODE) {
    node = node->children;
    depth++;
    continue;
}
while (node->next == NULL) {
    if (depth == 0) {
        return NULL;
    }
    node = node->parent;
    depth--;
}
node = node->next; 

Mitigation

The PHP project publishes security fixes only for its supported release lines. PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0 and 8.1 are End-of-Life and will not receive any public updates to address this issue.

Until an upgrade is possible, disable the soap extension where it is not used, and limit the size of request bodies that reach SoapServer endpoints at the web server or proxy, which makes very deep documents harder to send.

Users of the affected components should apply one of the following mitigations:

  • Upgrade to PHP 8.2.34, 8.3.35, 8.4.26, 8.5.11, or later.
  • Leverage a commercial support partner like HeroDevs (NES for PHP) for post-EOL security support.

Credits

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
High
ID
CVE-2026-91765
PROJECT Affected
PHP
Versions Affected
<8.2.34, >=8.3.0 <8.3.35, >=8.4.0 <8.4.26, >=8.5.0 <8.5.11
NES Versions Affected
Published date
September 25, 2026
≈ Fix date
October 23, 2026
Fixed in
Category
Uncontrolled Recursion
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
PHP
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.