CVE-2026-91769
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 OpenSSL extension provides TLS for PHP streams, so connections through ssl://, tls://, https:// and ftps:// can verify that the server's certificate belongs to the host being contacted.
An Authentication Bypass vulnerability (CVE-2026-91769) has been identified in the TLS peer name verification of PHP's OpenSSL extension, which allows an attacker who holds a certificate that a trusted certificate authority issued for another identity, but whose Common Name carries the expected host name, to have that certificate accepted for the expected host and impersonate it. PHP tracks this issue as GHSA-vvx9-73fr-5jjx.
Per MITRE CWE-297: The product communicates with a host that provides a certificate, but the product does not properly ensure that the certificate is actually associated with that host.
This issue affects all versions of PHP 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, including the End-of-Life release lines PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0 and 8.1 through their final releases.
Details
Module Info
- Product: PHP
- Affected packages:
php-src(ext/openssl) - Affected versions: <8.2.34, >=8.3.0 <8.3.35, >=8.4.0 <8.4.26, >=8.5.0 <8.5.11
- GitHub repository: https://github.com/php/php-src
- Published packages: https://www.php.net/downloads
- Package manager: N/A
- Fixed in:
- OSS PHP 8.2.34, 8.3.35, 8.4.26, 8.5.11
- NES for PHP 5.6.1 (based on PHP 5.6.40)
- NES for PHP 7.2.1 (based on PHP 7.2.34)
- NES for PHP 7.4.1 (based on PHP 7.4.33)
Vulnerability Info
This Medium-severity vulnerability is found in the OpenSSL extension of PHP before 8.2.34, 8.3 before 8.3.35, 8.4 before 8.4.26 and 8.5 before 8.5.11. The CVE record does not list the End-of-Life PHP 5.6, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0 and 8.1 release lines, but they carry the same code and never received the upstream fix. The PHP project scores it 4.3 under CVSS 3.1 (CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N).
When a TLS stream has verify_peer and peer name verification enabled, PHP checks that the server certificate matches the expected peer name. It first compares the name against the certificate's subjectAltName entries and, when none matches, falls back to the certificate's Common Name (CN). In PHP 7.4.33 the check reads:
if (peer_name) {
if (php_openssl_matches_san_list(peer, peer_name)) {
return SUCCESS;
} else if (php_openssl_matches_common_name(peer, peer_name)) {
return SUCCESS;
} else {
return FAILURE;
}
} else {
return FAILURE;
}
RFC 6125 requires a client to ignore the Common Name once the certificate presents a DNS, SRV or URI identity in its subjectAltName. A certificate authority that issues a certificate validates the identities in the subjectAltName, but may leave an unvalidated value in the Common Name. Because PHP fell back to the Common Name anyway, a certificate whose subjectAltName names another host but whose Common Name holds the expected name was accepted, so a certificate trusted for one name could be used to impersonate another.
Exploitation needs a PHP application acting as a TLS client with verify_peer and a peer name, through ssl://, tls://, https:// or ftps:// streams, and an attacker in a position to intercept the connection who holds such a certificate from a certificate authority the client trusts. The CVSS vector rates the attack vector as adjacent network. This applies to any SAPI. Applications that make no outgoing TLS connections from PHP are not exposed.
The fix records whether the certificate presents a DNS, URI or SRV identity and, if so, no longer consults the Common Name. IP address identities are left out because they are outside the scope of RFC 6125. A mismatch now reports that the subjectAltName did not match. In the upstream code the check reads:
if (php_openssl_matches_san_list(peer, peer_name, &has_service_id)) {
return SUCCESS;
} else if (has_service_id) {
/* CN must be ignored if the certificate presents a service identity. */
php_error_docref(NULL, E_WARNING,
"Peer certificate subjectAltName did not match expected name `%s'",
peer_name);
return FAILURE;
} else if (php_openssl_matches_common_name(peer, peer_name)) {
return SUCCESS;
} else {
return FAILURE;
}
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.
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
- Cantina (finder)
- David Korczynski (finder)
- benzdeus (finder)
- Jakub Zelenka (remediation)