Product: PHP
Affected Versions: PHP < 8.2.31, < 8.3.31, < 8.4.21, < 8.5.6
Severity: High
CWE: CWE-416 (Use After Free)
Reporter: Brett Gervasoni
Date: 2026-05-07
PHP Advisory: https://github.com/php/php-src/security/advisories/GHSA-85c2-q967-79q5
CVE: CVE-2026-6722
PHP's SOAP extension contained a use-after-free vulnerability in the handling of SOAP object references. A crafted SOAP payload using an Apache map could cause ext-soap to retain a stale object reference, then later resolve an href to memory that had already been released. The PHP advisory states that attacker-controlled allocations after the free can make this condition exploitable for remote code execution.
Any PHP application using the vulnerable PHP SOAP extension to parse attacker-controlled SOAP data is affected. In practice, this means applications with ext-soap installed and enabled that process untrusted SOAP messages through PHP SOAP functionality such as SoapServer or SoapClient.
ext-soap deduplicates objects in a SOAP XML graph by storing plain PHP objects in SOAP_GLOBAL(ref_map). The key is derived from the libxml2 node pointer, and the value is the PHP object associated with that node. This tracking occurs when ext-soap records an XML reference during decoding.
The issue was that the stored object was not given an additional reference count before being inserted into the SOAP reference map. In ordinary object graphs this did not usually matter because the decoded object graph retained the objects strongly enough for the duration of processing.
The Apache map behavior changed that lifetime assumption. By using two map entries with the same key, a crafted payload could first create and track an object, then immediately overwrite the map entry with an empty value. That overwrite releases the object from the temporary map while SOAP_GLOBAL(ref_map) still points at it.
When a later node resolves href="#stale", ext-soap looks up the stale entry and reuses the freed object slot. With subsequent string allocations, an attacker can influence the reclaimed memory region and turn the stale reference into a remote code execution primitive.
The vulnerable sequence described by PHP is:
apache:Map node.id, causing ext-soap to remember the object in SOAP_GLOBAL(ref_map).href pointing back to the freed object's id.The core lifetime bug is that the SOAP reference map held a pointer-like association to the object without owning a reference that would keep the object alive until reference-map cleanup.
The advisory's proof of concept uses a SOAP body shaped like this:
<test>
<map xsi:type="apache:Map" xmlns:apache="http://xml.apache.org/xml-soap">
<item>
<key>somekey</key>
<value id="stale"><object>Stale</object></value>
</item>
<item>
<key>somekey</key>
<value></value>
</item>
</map>
<stale href="#stale"/>
</test>
The first map entry creates the tracked object. The second entry with the duplicate key removes the map's strong reference to that object. The final href then resolves through the stale reference-map entry.
PHP fixed the vulnerability by making the SOAP reference map own the objects it tracks. In practical terms, the object reference count is increased before insertion into SOAP_GLOBAL(ref_map), and a destructor is configured so those references are released when SOAP processing is complete. The remediation was developed by Ilija Tovilo and reviewed by Niels Dossche.