What these two advisories fix
Both advisories target ext/openssl, the extension that handles TLS encryption for PHP streams. They do not concern the visitors of your site: they concern the connections your PHP code opens to the outside, for example a file_get_contents('https://…'), a fopen on an https URL or a stream_socket_client on tls://.
In those cases, PHP checks that the certificate presented by the remote server matches the requested host name. This is the verify_peer_name option, enabled by default. Both flaws sit in that check. The CVE-2026-91769 advisory (GHSA-vvx9-73fr-5jjx) describes a verification that is too permissive. The CVE-2026-91767 advisory (GHSA-xr7j-rvgx-xq5p) describes an out-of-bounds read in the comparison of wildcard names. Both were published on the same day, 24 September 2026, and are fixed by the same versions.
The essentials in seven points
- CVE-2026-91769 — moderate severity, CVSS 3.1 score of 4.3. Peer name verification looks at the
subjectAltNameentries first, then falls back to the Common Name even when the certificate presents a DNS SAN that does not match. - CVE-2026-91767 — moderate severity, CVSS 3.1 score of 6.5 (CWE-122). In
php_openssl_matches_wildcard_name(), a length underflow passed tomemchr()causes an out-of-bounds read when the certificate's wildcard name has more literal characters than the host being verified. - Fixed versions — PHP 8.2.34, 8.3.35, 8.4.26 and 8.5.11, for both flaws. Versions 8.4.26 and 8.5.11 appear in the PHP changelog dated 24 September 2026.
- Who is affected — clients that rely on the default value of
verify_peer_name, throughfile_get_contents(),fopen()andstream_socket_client()onhttps://andtls://. - Workaround — the advisory gives none. Disabling verification is not one, it is one more flaw.
- Branches 8.1 and earlier — end of life, no upstream fix. Distribution fixes or third-party backports may exist: check package by package.
- Exploitation — in the sources we consulted, we found no observed exploitation of these two flaws.
What these flaws allow, and what they do not
CVE-2026-91769 allows host spoofing. A certificate that your client trusts for one host can be used to impersonate another one, if its Common Name contains the targeted name. RFC 6125 says to ignore the CN when a DNS SAN is present, and PHP did not. The advisory considers the case mostly relevant for private PKI, meaning an internal authority that issues certificates for many services.
CVE-2026-91767 allows a PHP client to be crashed. A malicious server, or one with a trusted authority, can trigger the out-of-bounds read during verification: this is a denial of service. The advisory states that the outcome only affects the accept or reject decision and returns no heap content. One honest caveat: the CVSS vector rates confidentiality High and availability None, which does not match the text of the impact. We flag it without taking sides.
What they do not allow. The advisory describes no code execution. Neither flaw is triggered by a visitor request reaching your site. Both vectors are of the adjacent network type (AV:A): the attacker must be close to the communication, not anywhere on the Internet.
Rated moderate: is it urgent?
An honest answer: nothing in the sources we consulted indicates that these flaws are being exploited. We claim nothing beyond that. They are not comparable to PHP2Shell (CVE-2026-109618 and CVE-2026-109619), which targets the interpreter itself and is triggered by an anonymous HTTP request. That flaw is covered separately in our PHP2Shell article; the latest version of your branch, which that article asks you to install, also contains these fixes.
Urgency is therefore graded. It is real if your code calls external URLs with PHP streams (payment APIs, outgoing webhooks, feed imports, licence checks) or internal services whose certificates come from a private PKI. It is much lower for a showcase site that makes no outgoing calls. In both cases the fix stays within the same branch: fit it into your next maintenance window rather than postponing it without a date.
Measure your exposure in four steps
Read the PHP version actually served
On the server, run
php -r 'echo PHP_VERSION, PHP_EOL;'. Do not rely onOPENSSL_VERSION_TEXT: it is not the system OpenSSL library that is fixed, it is the extension code, so the PHP version is what counts. Beware, the CLI may differ from what your sites serve: on a server that hosts several branches, also read the version of each PHP-FPM pool (see the verification step below). On cPanel, the version is read per domain, see our guide to the PHP selector.Look for calls that go through PHP streams
List the outgoing calls that carry a literal URL in the code:
grep -rnE "(file_get_contents|fopen)\(\s*['\"]https?://|stream_socket_client\(\s*['\"]tls://" /var/www --include='*.php'. On a cPanel hosting account, replace/var/wwwwith/home. Complete with calls whose URL comes from a variable:grep -rnE "(file_get_contents|fopen|stream_socket_client)\(\s*\$" /var/www --include='*.php'. Think about WordPress plugins and thevendorfolder: outgoing calls often hide there.Spot verifications that are already disabled
Run
grep -rn "verify_peer_name" /var/www --include='*.php'. A value offalsemeans no host name is verified at all: that code is exposed to far more than these two advisories, whatever the PHP version. Fix it before anything else.Rank your sites
A site is a priority if it combines a branch below the floor in the table that follows and outgoing calls through streams. Calls made through the cURL extension are not cited by the advisory, which lists PHP streams. WordPress and most HTTP libraries generally use cURL when it is available, but fall back to streams otherwise: do not rule them out without checking.
Which version to install for your branch
Scroll the table
| PHP branch | Minimum fixed version | Status |
|---|---|---|
| 8.5 | 8.5.11 | Fixed. Install the latest 8.5 available. |
| 8.4 | 8.4.26 | Fixed. Install the latest 8.4 available. |
| 8.3 | 8.3.35 | Fixed. Install the latest 8.3 available. |
| 8.2 | 8.2.34 | Fixed. Plan to leave this branch, see the checklist linked at the end of the article. |
| 8.1 and earlier (5.6 to 8.1) | No upstream version | End of life. Distribution fix or third-party backport to verify, otherwise migrate. |
Apply the fix for your environment
Debian and Ubuntu
Refresh the index with
sudo apt update, then upgrade the packages of your branch withsudo apt install --only-upgrade 'php8.3*'(replace 8.3 with your branch). To see what is pending:apt list --upgradable 2>/dev/null | grep -i php. Distributions often fix through a backport without changing the upstream number: read the package log withapt changelog php8.3-cli | grep -i CVE-2026-91769. With a third-party repository such as Sury, the same commands apply.RHEL, AlmaLinux and Rocky Linux
Run
sudo dnf update 'php*'. If you use a module stream, the branch follows the enabled module:dnf module list --enabled phpshows it. Then check the log withrpm -q --changelog php-cli | grep -i CVE-2026-91769. With a third-party repository, package names change: adapt the pattern to whatrpm -qa 'php*'returns.cPanel: EasyApache 4 and the PHP selector
EasyApache 4 branches are packages named
ea-php83,ea-php84, and so on. If you have root, list them withrpm -qa 'ea-php*' | sortthen update them withsudo dnf update 'ea-php*'. Read the log withrpm -qa --changelog 'ea-php83*' | grep -i CVE-2026-91769and the real version with/opt/cpanel/ea-php83/root/usr/bin/php -v. On shared hosting, the host does the update: your part is to check, in the cPanel PHP selector (MultiPHP Manager, or Select PHP Version on CloudLinux), that each domain runs on a fixed branch.Docker
An image is not fixed in place: rebuild it, pulling the updated base, with
docker build --pull --no-cache -t your-image ., ordocker compose build --pull --no-cachewith Compose, then restart withdocker compose up -d. Check the result inside the container withdocker run --rm your-image php -v. A floating tag such asphp:8.4-fpmonly moves if the upstream image was rebuilt: the printed number is what counts, not the tag name.Restart the PHP services
PHP-FPM and Apache keep the old code in memory until they are reloaded. On Debian or Ubuntu:
sudo systemctl restart php8.3-fpm(adapt the branch), andsudo systemctl restart apache2if you usemod_php. On RHEL or AlmaLinux:sudo systemctl restart httpd. On cPanel with PHP-FPM,systemctl list-units 'ea-php*'gives the exact name of the service to restart.Check the version actually served
The CLI is not the web service. Query the FPM binary:
php-fpm8.3 -von Debian and Ubuntu,php-fpm -von RHEL and derivatives, or the domain's version in cPanel. The number must reach the floor of your branch, or its log must cite CVE-2026-91769. Finish with a test outgoing call:php -r 'echo strlen(file_get_contents("https://your-domain.com/")), PHP_EOL;'.
If your branch is end of life (8.1 and earlier)
According to HeroDevs, PHP branches 5.6 to 8.1 are end of life and receive no upstream fix for these flaws. Do not assume anything either way. Your distribution may have backported the fix into its package: it is possible, it is not guaranteed, and it is checked package by package, with the change log (apt changelog, rpm -q --changelog) and the distribution's security tracker. Third-party vendors also offer backports for abandoned versions.
Without a confirmed fix, you have three levers. The first is migrating to a maintained branch, 8.3 or 8.4 after testing your site: the method is in our PHP migration checklist. The second is to limit the outgoing calls of that code to hosts whose certificates you control. The third is to restrict the server's outgoing traffic at the firewall. The last two reduce exposure, they fix nothing.
Never set verify_peer_name to false
Faced with a certificate error, the temptation is to add verify_peer_name => false in a stream_context_create. That is worse than the flaw: no host name is verified anymore, so any trusted certificate passes for any host. The advisory gives no workaround, and this option is not one. When a connection fails after the update, repair the certificate.
A third OpenSSL fix in the same quarter
CVE-2026-14355 is a separate flaw: memory corruption in openssl_encrypt() with the AES-WRAP-PAD algorithm (GH-22187). According to the PHP changelog (https://www.php.net/ChangeLog-8.php), it is fixed in PHP 8.4.23, dated 3 July 2026, and in PHP 8.5.8, dated 2 July 2026. It affects encryption, not TLS verification: it changes nothing in the exposure test above.
If you install 8.4.26 or 8.5.11 or later, you already have this fix. For branches 8.2 and 8.3, we do not cite a version, as we have not verified it: read your package log to see whether CVE-2026-14355 appears in it.
Troubleshooting after the update
The fix tightens a check. Some calls that used to pass may therefore fail now, and that is the expected consequence of the fix, not a regression. The case to test first is an internal service whose certificate comes from a private authority. Here are the real messages you may meet and the matching remedy.
Errors you may meet and their remedies
SSL operation failed with code 1thencertificate verify failed— typical full message:stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed. Probable cause: the certificate presents a DNS SAN that does not contain the host being called, but its CN does. The old check accepted it by falling back to the CN, the new one rejects it. Read the certificate withopenssl s_client -connect interne.your-domain.com:443 -servername interne.your-domain.com </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName. Remedy: reissue the certificate with a correct DNS SAN for every name used, never disable verification.file_get_contents(): Failed to enable crypto— warning that accompanies the previous one. Read the full message that follows: depending on the version, you may also findPeer certificate CN=… did not match expected CN=…. Same cause, same remedy.- A certificate with no SAN at all, only a CN, still fails — the fix keeps the CN fallback for certificates without a service identifier. The cause is therefore elsewhere: authority not trusted by the client, host called by an alias or an IP address missing from the certificate, expired certificate. Remedy: add the internal authority to
cafilein the stream context, and reissue the certificate with a SAN. child exited on signal 11 (SIGSEGV)in the PHP-FPM log — a worker crashing during an outgoing TLS call is compatible with CVE-2026-91767. Do not conclude from that sign alone: check the version, update and see whether the pattern disappears.php -vstill shows the old version — service not restarted, CLI and FPM on different branches, Docker image rebuilt without--pull, or the domain's version unchanged in cPanel. Go back to the verification step.- The distribution log does not cite the CVE — its absence proves neither that the fix is there nor that it is missing. Consult the distribution's security tracker, and failing that compare the upstream number with the floor in the table.
Build the update into your routine
Record the floor in your inventory
Add a "minimum version" column per branch to your fleet inventory, with the values from the table. A version below the floor then becomes visible without any research.
Schedule PHP updates
A PHP security fix is a minor update within the same branch: plan a regular slot rather than a project for each advisory, with a service restart and a check of the version served.
Test an outgoing call after each update
Replay
php -r 'echo strlen(file_get_contents("https://your-domain.com/")), PHP_EOL;'from each server, and a call to your internal services. A certificate error then shows up immediately, not at a customer's.Connect this fix to the rest of your monitoring
For the method of surveying a fleet, read the PHP version inventory for a client fleet. For the most critical flaw of the moment, see PHP2Shell. To change a site's version, follow the cPanel PHP selector guide. For a branch that is ending, go back to the PHP 8.2 migration checklist.