This is less a front-door master key and more a brittle latch that only fails on one oddly wired side entrance
CVE-2026-7261 is a SoapServer use-after-free in PHP when an application uses SOAP_PERSISTENCE_SESSION, which stores the handler object in session state across requests. The bug is hit on an error path: if a SOAP header handler throws or returns failure, PHP frees the handler object but later still reuses it during session writeback. Affected upstream branches are PHP 8.2.0-8.2.30, 8.3.0-8.3.30, 8.4.0-8.4.20, and 8.5.0-8.5.5; fixed versions are 8.2.31, 8.3.31, 8.4.21, and 8.5.6.
The vendor-side reality is already telling you this is not a generic critical. PHP's own advisory scores it Moderate with CVSS v4 6.3, while NVD's CVSS v3.1 auto-style scoring shows 9.8 because it models the bug as a raw network-reachable memory safety issue and ignores the deployment friction. In real estates, the attacker needs a reachable SOAP endpoint, the app must specifically use SoapServer::setClass() with SOAP_PERSISTENCE_SESSION, and the exploit path depends on an error-producing header handler plus difficult heap control; that combination is why this lands in MEDIUM, not CRITICAL.
5 steps from start to impact.
Find a live PHP SOAP server
curl, Burp Suite, or a custom HTTP client. This is not 'all PHP on the internet'; it is only applications that actually expose ext-soap server functionality.- A SOAP endpoint is network reachable
- The endpoint is backed by PHP
SoapServerrather than some other stack
- SOAP is now a minority pattern in many enterprises
- Most internet scanning can identify PHP broadly but not confirm
SoapServerusage
/wsdl or SOAP-style POST behavior, but commodity vuln scanners have weak direct coverage for this specific code path.Hit the narrow vulnerable configuration
SoapServer::setClass() and enable SOAP_PERSISTENCE_SESSION, which serializes the handler object into session storage between requests, per the PHP manual. Without that exact persistence mode, this CVE does not fire.- Application uses
SOAP_PERSISTENCE_SESSION - PHP
ext-soapis installed and active - The vulnerable branch/version is deployed
- This flag is uncommon and app-specific
- You cannot infer this setting from a banner or package scan alone
- Many SOAP implementations use request-scoped handlers instead
SOAP_PERSISTENCE_SESSION.Trigger the header-fault error path
- The endpoint accepts attacker-controlled SOAP input
- A header handler exists and can be induced to throw or fail
- Malformed XML alone is not enough; the attacker needs the right application behavior
- Many SOAP services do little or no custom header handling
php-fpm logs.Reuse the session and touch the dangling object
- Attacker can maintain or replay the same session
- The allocator state is favorable enough for useful reuse of freed memory
- Heap shaping is hard in this path
- A single-request execution model reduces attacker control
- Modern hardening often turns memory bugs into crashes instead of RCE
php-fpm child respawns, and crash-looping around SOAP requests.Turn corruption into meaningful impact
- Advanced exploit development time
- Target-specific reliability testing
- No public weaponized exploit found
- No KEV listing or active exploitation evidence found
- The path is too narrow for spray-and-pray internet exploitation
setPersistence(SOAP_PERSISTENCE_SESSION). For a MEDIUM verdict there is no noisgate mitigation SLA, so use this as immediate scoping work and go straight toward the 365-day remediation window.SOAP_PERSISTENCE_SESSION or switch to request-scoped handling to kill the vulnerable path without waiting for a full stack uplift. There is no mitigation SLA for MEDIUM, but this is the cleanest interim risk reduction if you discover internet-facing SOAP services.php-fpm worker respawns, segfaults, core dumps, and bursts of SOAP faults from the same client/session. This does not remove the bug, but it raises the odds you catch probing or unreliable exploit development before it becomes an outage.- Hiding PHP version banners does not help; the attacker's real problem is endpoint discovery and app behavior, not just banner parsing.
- Composer/SCA-only dependency scanning does not reliably catch this because
ext-soapis a built-in/runtime component, not just an application package incomposer.lock. - A generic WAF rule for malformed XML does not guarantee coverage; the vulnerable path depends on valid-enough SOAP requests that trigger application header-handler failure.
The supporting signals.
| In-the-wild status | No authoritative exploitation evidence found in the sourced material. CISA KEV: not listed. |
|---|---|
| Proof-of-concept availability | A vendor-authored reproducer exists in the GitHub advisory (GHSA-m33r-qmcv-p97q), but I found no public weaponized exploit repo or repeatable RCE chain. |
| EPSS | User-supplied EPSS is 0.0007; third-party mirrors around publication also show roughly 0.00059%-0.06% probability and an extremely low percentile. Read that as 'little market interest,' not zero risk. |
| KEV status | No. Not present in the CISA Known Exploited Vulnerabilities catalog. |
| CVSS discrepancy | NVD lists CVSS v3.1 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H), but the PHP CNA advisory uses CVSS v4 6.3 with AT:P, which better reflects the extra deployment prerequisite. |
| Affected versions | Upstream affected: 8.2.0-8.2.30, 8.3.0-8.3.30, 8.4.0-8.4.20, 8.5.0-8.5.5. |
| Fixed versions | Upstream fixed: 8.2.31, 8.3.31, 8.4.21, 8.5.6. Distro examples: Debian php8.2 8.2.31-1~deb12u1, Debian php8.4 8.4.21-1~deb13u1, Amazon Linux 2 php8.2 fixed in ALAS2PHP8.2-2026-011. |
| Exposure/scanning reality | There is no reliable internet census for SOAP_PERSISTENCE_SESSION usage. Shodan/Censys can help find public PHP or SOAP endpoints, but they cannot prove this specific runtime flag from the outside. |
| Disclosure timeline | PHP released fixes on 2026-05-07; NVD/CVE publication shows 2026-05-10. |
| Reporter / source | Source/CNA is PHP Group; advisory published in php/php-src GitHub Security Advisories. |
Sources.
Why this verdict
- Baseline down from 9.8: the raw memory-corruption class is scary, but the PHP CNA itself scores this
6.3because exploitation needs extra attack requirements, not just a socket. - Population is narrow: the attacker needs a public or reachable SOAP service using PHP
ext-soap,SoapServer::setClass(), and specificallySOAP_PERSISTENCE_SESSION; each prerequisite compounds downward pressure. - Impact is not cleanly reliable: the advisory says SOAP usually handles one request per PHP request, so controlling the freed chunk is unlikely; in many real deployments the plausible outcome is crash or unstable worker behavior before dependable RCE.
Why not higher?
I am not taking this to HIGH or CRITICAL because it is not a universal pre-auth path against generic PHP. The attack requires a rare application pattern and a brittle error path, and there is no KEV entry, no sourced in-the-wild exploitation evidence, and no public weaponized exploit chain showing reliable code execution.
Why not lower?
I am not dropping this to LOW because the bug is still remotely triggerable with no authentication if the vulnerable app pattern exists. It sits in a server-side memory-safety path, so a reachable affected SOAP service can still suffer process crashes or possibly information disclosure, which is more than backlog-only hygiene.
Crowdsourced verification payload.
Run this on the target PHP application host. Save it as check-cve-2026-7261.sh and run bash check-cve-2026-7261.sh /var/www to also inspect deployed code for SOAP_PERSISTENCE_SESSION; no root is required unless the PHP binary or app tree is restricted.
#!/usr/bin/env bash
# check-cve-2026-7261.sh
# Detect likely exposure to CVE-2026-7261 on a host.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
APP_PATH="${1:-}"
PHP_BIN="${PHP_BIN:-php}"
ver_lt() {
# returns 0 if $1 < $2
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" != "$2" ] && return 1
[ "$1" = "$2" ] && return 1
return 0
}
in_vuln_range() {
local v="$1"
if ver_lt "$v" "8.2.31" && ! ver_lt "$v" "8.2.0"; then return 0; fi
if ver_lt "$v" "8.3.31" && ! ver_lt "$v" "8.3.0"; then return 0; fi
if ver_lt "$v" "8.4.21" && ! ver_lt "$v" "8.4.0"; then return 0; fi
if ver_lt "$v" "8.5.6" && ! ver_lt "$v" "8.5.0"; then return 0; fi
return 1
}
if ! command -v "$PHP_BIN" >/dev/null 2>&1; then
echo "UNKNOWN: php binary not found in PATH"
exit 2
fi
PHP_VERSION="$($PHP_BIN -r 'echo PHP_VERSION;' 2>/dev/null)"
if [ -z "$PHP_VERSION" ]; then
echo "UNKNOWN: unable to determine PHP version"
exit 2
fi
SOAP_LOADED="$($PHP_BIN -m 2>/dev/null | awk 'BEGIN{IGNORECASE=1} /^soap$/{print "yes"}')"
if [ "$SOAP_LOADED" != "yes" ]; then
echo "UNKNOWN: ext-soap not loaded in this PHP SAPI; verify web SAPI separately"
exit 2
fi
if ! in_vuln_range "$PHP_VERSION"; then
echo "PATCHED: PHP $PHP_VERSION is outside the affected upstream ranges"
exit 0
fi
if [ -z "$APP_PATH" ]; then
echo "UNKNOWN: PHP $PHP_VERSION is in an affected range and ext-soap is loaded; rerun with app path to check for SOAP_PERSISTENCE_SESSION usage"
exit 2
fi
if [ ! -d "$APP_PATH" ]; then
echo "UNKNOWN: app path '$APP_PATH' does not exist or is not a directory"
exit 2
fi
MATCHES=$(grep -RInE 'SOAP_PERSISTENCE_SESSION|setPersistence\s*\(\s*1\s*\)' "$APP_PATH" 2>/dev/null | head -n 20 || true)
if [ -n "$MATCHES" ]; then
echo "VULNERABLE: PHP $PHP_VERSION is affected, ext-soap is loaded, and app code appears to use SOAP_PERSISTENCE_SESSION"
echo "$MATCHES"
exit 1
fi
echo "UNKNOWN: PHP $PHP_VERSION is affected and ext-soap is loaded, but no obvious SOAP_PERSISTENCE_SESSION usage was found under $APP_PATH"
exit 2