You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Regression with MySQL 4.1 after mysqlnd security fix GHSA-r6x9-5r99-36j7 #23956
Warning: mysqli::query(): Premature end of data (mysqlnd_wireprotocol.c:1018) in /app/test.php on line 12
Warning: mysqli::query(): EOF packet shorter than expected in /app/test.php on line 12
Fatal error: Uncaught Error: Call to a member function fetch_assoc() on false in /app/test.php:12
Stack trace:
#0 {main}
thrown in /app/test.php on line 12
Expected result
The SELECT 1 query should execute successfully, as it did in previous patch versions.
It looks like this behavior was introduced in the latest security releases across PHP 8.2 through 8.5, likely related to the changes in GHSA-r6x9-5r99-36j7: GHSA-r6x9-5r99-36j7
I am not a C developer, but while checking the source code of php_mysqlnd_eof_read() in mysqlnd_wireprotocol.c, I noticed a comment mentioning that MySQL 4.1 sends 1-byte EOF packets.
Could the new packet boundary checks be accidentally treating these valid 1-byte legacy packets as premature/truncated data?
PHP Version
PHP 8.5.11 (cli) (built: Sep 24 2026 19:06:49) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.11, Copyright (c) Zend Technologies
with Zend OPcache v8.5.11, Copyright (c), by Zend Technologies
Just to clarify. Do you really mean MySQL 4.1 that has been EOL since 2006 (extended support till 2009)? If so, I'm not sure I will be able to test it - such old server is long time out of our support too.
I also ran the mysqli/PDO MySQL tests after the change: 86 passed, 0 failed.
I am not familiar enough with the mysqlnd internals to say whether this is the correct or safe fix, but it may help to identify where the regression was introduced.
If it helps, I can also provide the exact Docker commands I used. The image needs one extra step because the default user still uses the old MySQL password authentication.
According to this RFC https://wiki.php.net/rfc/min_supported_versions_php_8_6#mysql_573_and_mariadb_1024 we no longer support MySQL versions older than MySQL 5.7.3. While it's not a hard limit, I don't think we should be expected to fix bugs that only happen with unsupported MySQL versions. However, if the issue points to a bug that could happen with modern versions, then it should still be fixed.
Thanks for pointing to the RFC. I'm not sure whether that policy also applies to the existing 8.2–8.5 branches, since the RFC is for PHP 8.6, and this is a regression between patch releases (e.g. 8.4.25 → 8.4.26).
mysqlnd_wireprotocol.c still contains explicit handling for pre-5.x servers, e.g. the 1-byte EOF branch in php_mysqlnd_eof_read() and the pre41 handling in php_mysqlnd_greet_read(). The new BAIL_IF_NOT_ENOUGH_DATA right after reading the first byte makes that branch unreachable. So it looks like an unintended side effect of the security fix rather than a deliberate drop of support.
#24432 fixes this without weakening the security checks. The length check is only moved into the ERROR_MARKER branch, which is the only branch that reads further data. All ghsa-r6x9-5r99-36j7 tests still pass, and two new fake-server tests cover the 1-byte packets.
Activity
iluuu1994 commentedon Sep 28, 2026
@bukka said he'll have a look next week.
bukka commentedon Sep 28, 2026
Just to clarify. Do you really mean MySQL 4.1 that has been EOL since 2006 (extended support till 2009)? If so, I'm not sure I will be able to test it - such old server is long time out of our support too.
jeroenvdkolff commentedon Sep 28, 2026
Yes, I really mean MySQL 4.1. I know it is very old and long out of support.
I was able to reproduce it locally with this Docker image:
I also tested a very small change in
ext/mysqlnd/mysqlnd_wireprotocol.c, around lines 1015–1020:With this change, PHP 8.5.11 works again with MySQL 4.1.
I rebuilt PHP 8.5.11 with the change and confirmed that the same SELECT 1 test works again:
I also ran the mysqli/PDO MySQL tests after the change: 86 passed, 0 failed.
I am not familiar enough with the mysqlnd internals to say whether this is the correct or safe fix, but it may help to identify where the regression was introduced.
If it helps, I can also provide the exact Docker commands I used. The image needs one extra step because the default user still uses the old MySQL password authentication.
kamil-tekiela commentedon Sep 28, 2026
According to this RFC https://wiki.php.net/rfc/min_supported_versions_php_8_6#mysql_573_and_mariadb_1024 we no longer support MySQL versions older than MySQL 5.7.3. While it's not a hard limit, I don't think we should be expected to fix bugs that only happen with unsupported MySQL versions. However, if the issue points to a bug that could happen with modern versions, then it should still be fixed.
jeroenvdkolff commentedon Oct 26, 2026
Thanks for pointing to the RFC. I'm not sure whether that policy also applies to the existing 8.2–8.5 branches, since the RFC is for PHP 8.6, and this is a regression between patch releases (e.g. 8.4.25 → 8.4.26).
mysqlnd_wireprotocol.cstill contains explicit handling for pre-5.x servers, e.g. the 1-byte EOF branch inphp_mysqlnd_eof_read()and thepre41handling inphp_mysqlnd_greet_read(). The newBAIL_IF_NOT_ENOUGH_DATAright after reading the first byte makes that branch unreachable. So it looks like an unintended side effect of the security fix rather than a deliberate drop of support.#24432 fixes this without weakening the security checks. The length check is only moved into the
ERROR_MARKERbranch, which is the only branch that reads further data. Allghsa-r6x9-5r99-36j7tests still pass, and two new fake-server tests cover the 1-byte packets.