The PHP team shipped PHP 8.5.11 on September 24, 2026, and it's a security release. It fixes 11 CVEs. The worst is a high severity bug that lets anyone crash a SoapServer endpoint with a single request. PHP 8.3.35 and 8.2.34 went out the same day with the same 11 fixes, and 8.4.26 is tagged with them too.

Here's what's in it:

  • Unbounded recursion in the SOAP server's XML handling, reachable without authentication (CVE-2026-91765, high)
  • The http:// stream wrapper forwarding Authorization and Cookie headers to a different host on redirect (CVE-2026-91766)
  • PHP-FPM's listen.allowed_clients matching a whole IPv6 /96 instead of one address (CVE-2026-91768)
  • Two OpenSSL hostname verification bugs, one a fallback to the certificate CN and one a heap overread (CVE-2026-91769, CVE-2026-91767)
  • Fixes in Phar, mysqlnd, the SOAP client, stream filters, and PHP on Windows
  • A long list of bug fixes across DOM, Intl, generators, and the tracing JIT

Security Fixes

Crashing Any SoapServer Endpoint

After libxml2 parses a SOAP request, PHP runs its own cleanup pass, cleanup_xml_node(), over the document. That function recursed once per nesting level with no limit. Send a request body with 50,000 nested elements and the process runs out of stack and segfaults. Nested tags compress well, so the payload is a few kilobytes on the wire.

It needs no authentication, no WSDL, and no special configuration. Under PHP-FPM, each request kills the worker handling it, so a steady stream of them empties the pool and takes the endpoint offline. The advisory is clear that this is a denial of service, and the crash doesn't give an attacker control of the process.

Alexandre Daubois fixed it by capping XML depth at 2048 and rewriting the traversal to loop instead of recurse. The same patch covers two more recursive paths in the SOAP value decoder and the WSDL search, including href chains that could loop forever.

Advisory: GHSA-rgrp-mwpx-f6rm

Credentials Leaking Across Redirects

This one affects far more apps than the SOAP bug. If you pass an Authorization header through a stream context and let file_get_contents() follow redirects, which it does by default, PHP forwarded that header to wherever the redirect pointed:

$ctx = stream_context_create(['http' => [
    'header' => "Authorization: Bearer SECRET\r\nCookie: sid=abc",
    'follow_location' => 1,
]]);

file_get_contents('https://example.com/api', false, $ctx);

If example.com answers with a redirect to another host, that host receives your bearer token and session cookie. A redirect from HTTPS to HTTP sends them over the network in plain text. It's the same class of bug libcurl fixed back in 2018.

After the fix, the wrapper compares the scheme, host, and port of each hop. When they change, it strips Authorization, Cookie, and Proxy-Authorization, and keeps them stripped for every hop after that.

Advisory: GHSA-fpwc-w8rq-cr92

FPM Allowed Clients on IPv6

The IPv6 branch of FPM's client check compared 12 bytes of a 16-byte address. So listen.allowed_clients = ::2 also let in ::1, and every entry quietly widened to a /96 network. This only matters if FPM listens on IPv6 TCP and you rely on allowed_clients as the boundary. Unix sockets, IPv4-only setups, and pools behind a firewall aren't affected.

Advisory: GHSA-62xp-839h-2637

OpenSSL Hostname Verification

Jakub Zelenka fixed two bugs in how PHP checks a server certificate against the hostname you asked for. Both hit any https:// or tls:// client stream using the default verify_peer_name.

The first let a certificate pass on its Common Name even when its subjectAltName entries didn't match, which RFC 6125 forbids. A certificate trusted for one name could impersonate another. The second is a length underflow in wildcard matching, where a crafted certificate makes PHP read far past the end of a buffer and crash.

Advisories: GHSA-vvx9-73fr-5jjx, GHSA-xr7j-rvgx-xq5p

The Rest

  • SOAP client: an integer overflow in HTTP response parsing that a malicious server can turn into a heap overflow, on builds where the compiler drops the overflow check (GHSA-cj93-vc83-wgqv, CVE-2025-14181)
  • Phar: an integer overflow in TAR header parsing that allows archive entry injection (GHSA-j3wh-g957-2m85, CVE-2026-6103)
  • HTTP wrapper: an out-of-bounds read when a redirect has an empty Location header (GHSA-7875-c8px-7q5f, CVE-2026-93682)
  • Stream filters: an out-of-bounds read in convert.* filters when line-break-chars contains a NUL (GHSA-88hq-2827-7pg6, CVE-2026-92842)
  • mysqlnd: packet overreads in the wire protocol, rated low (GHSA-r6x9-5r99-36j7, CVE-2025-1218)
  • Windows: reserved device names like CON and NUL weren't rejected in file paths, so a user-supplied filename could open a device and hang the request (GHSA-9f67-6fw4-hpfp, CVE-2026-17545)

Other Fixes Worth Noting

Nested yield from got two fixes. One skipped items after you called valid() or next() on the inner generator (GH-15375), and the other yielded a value twice when a middle generator delegated again (GH-23301). A lone namespace separator no longer asks the autoloader for an empty class name (GH-23232), and array_keys() now returns an array with the right next index (GH-23576).

DOM and Intl account for most of the remaining memory safety work, with several use-after-free fixes in each. grapheme_strpos() and NumberFormatter stopped returning UTF-16 offsets where you'd expect grapheme or byte offsets (GH-23094). PDO_PGSQL scrollable cursors now work with PDO::ATTR_PREFETCH => 0, following the lazy fetch fixes in PHP 8.5.10. The tracing JIT fixed a crash on side traces for classes that missed the inheritance cache (GH-21710).

Upgrade Notes

No new features, this is a patch release. Schedule it rather than batching it, especially if you expose a SoapServer, run FPM over IPv6 with allowed_clients, or call authenticated APIs through file_get_contents().

One behavior change is worth knowing. If your code relied on credentials following a cross-origin redirect, those requests now go out without them. That was the bug, but it can look like a new 401 after the upgrade.

All four supported branches carry the same 11 fixes: 8.5.11, 8.4.26, 8.3.35, and 8.2.34. When we wrote this, php.net had announced 8.5.11, 8.3.35, and 8.2.34. PHP 8.4.26 is tagged in php-src and named as the patched version in every advisory, but its announcement hadn't gone up yet. Most people will pick these up through their distribution's packages or a Docker image, so check what your base image ships.

PHP 8.6.0 RC2 also went out the same day. It's the first release candidate despite the name, since a packaging mistake with RC1 meant the team skipped straight to RC2. Don't run it in production, but it's worth testing your app against it now.

References