CVE-2025-1218

Buffer Over-read
Affects
PHP
in
PHP
No items found.
Versions
<8.2.34, >=8.3.0 <8.3.35, >=8.4.0 <8.4.26, >=8.5.0 <8.5.11

Patch Available.

Exclamation circle icon
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 mysqlnd library implements the MySQL client protocol for the mysqli and PDO_MySQL extensions, and on PHP 5.6 for the legacy mysql extension when it is built against mysqlnd.

An Out-of-Bounds Read vulnerability (CVE-2025-1218) has been identified in the packet decoders of PHP's mysqlnd library, which allows a malicious or impersonated MySQL server to send truncated packets that make the PHP client read past the end of its packet buffer, which may expose memory contents or crash the process. PHP tracks this issue as GHSA-r6x9-5r99-36j7.

Per MITRE CWE-125: The product reads data past the end, or before the beginning, of the intended buffer.

This issue affects 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, which includes every End-of-Life release line from PHP 5.6 through 8.1, each through its final release.

Details

Module Info

Vulnerability Info

This Low-severity vulnerability is found in the mysqlnd library 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, including every End-of-Life release line from PHP 5.6 through 8.1, which never received the upstream fix. The PHP project scores it 3.4 under CVSS 3.1 (CVSS:3.1/AV:A/AC:H/PR:N/UI:N/S:C/C:L/I:N/A:N).

The MySQL protocol encodes many fields as length-encoded integers and strings whose size is given by their first byte. mysqlnd decodes the server's greeting, OK, EOF, authentication and change-user packets, result set headers and field definitions, prepared statement responses, rows and the sha256 public key exchange, plus the caching_sha2 exchange on the lines that support it. In these decoders it read each field first and only then checked whether it had gone past the end of the packet. In PHP 7.4.33 the OK packet decoder reads:

/* Everything was fine! */
packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
BAIL_IF_NO_MORE_DATA;

packet->last_insert_id = php_mysqlnd_net_field_length_ll(&p);
BAIL_IF_NO_MORE_DATA;

packet->server_status = uint2korr(p);
p+= 2;
BAIL_IF_NO_MORE_DATA;

A length-encoded integer can occupy up to nine bytes, and uint2korr() reads two, so a server that sends a packet ending in the middle of a field makes mysqlnd read beyond the bytes it received before BAIL_IF_NO_MORE_DATA notices. The prepared statement row decoder also trusted a field length shorter than the layout of its type. The reads go past the packet buffer, which is undefined behavior: they can crash the process, and the bytes read may end up in values returned to the application.

Exploitation needs an application that connects through mysqli or PDO_MySQL (or, on PHP 5.6, the mysql extension built with mysqlnd) to a MySQL server that the attacker controls or can impersonate, for example a connection without TLS on a network the attacker can reach, or a host name the attacker can influence. Applications that only connect to trusted servers over verified TLS are not exposed. HeroDevs' analysis notes that PHP 5.6 and 7.2 have no caching_sha2_password support, so that part of the upstream fix does not apply to them.

The fix bounds every read by the packet size: length-encoded values are decoded only if the remaining bytes can hold them, NUL-terminated strings are searched for within the packet, and short packets fail with a warning. In the upstream fix the same part of the OK packet decoder reads:

len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin));
if (UNEXPECTED(!len_ll.has_value)) {
    BAIL_PREMATURE_END;
}
packet->affected_rows = len_ll.value;

len_ll = php_mysqlnd_net_field_length_ll(&p, packet->header.size - (p - begin));
if (UNEXPECTED(!len_ll.has_value)) {
    BAIL_PREMATURE_END;
}
packet->last_insert_id = len_ll.value;

BAIL_IF_NOT_ENOUGH_DATA_EX(4);

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.

Until an upgrade is possible, connect only to trusted MySQL servers and use TLS with server certificate verification, so that an attacker cannot impersonate the server.

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

Vulnerability Details
Severity
Level
CVSS Assessment
Low
>=0 <4
Medium
>=4 <6
High
>=6 <8
Critical
>=8 <10
Low
ID
CVE-2025-1218
PROJECT Affected
PHP
Versions Affected
<8.2.34, >=8.3.0 <8.3.35, >=8.4.0 <8.4.26, >=8.5.0 <8.5.11
NES Versions Affected
Published date
September 25, 2026
≈ Fix date
October 23, 2026
Fixed in
Category
Buffer Over-read
Vex Document
Download VEXHow do I use it?
Sign up for the latest vulnerability alerts fixed in
PHP
Rss feed icon
Subscribe via RSS
or

By submitting the form I acknowledge receipt of our Privacy Policy.

Thanks for signing up for our Newsletter! We look forward to connecting with you.
Oops! Something went wrong while submitting the form.