From 6f14bee9803ea83bf76b31339f489ce52ac7e31c Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Wed, 8 Apr 2026 21:37:01 +0800 Subject: [PATCH 1/3] initial fix --- ext/standard/password.c | 6 ++++++ .../password/password_bcrypt_null_verify.phpt | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 ext/standard/tests/password/password_bcrypt_null_verify.phpt diff --git a/ext/standard/password.c b/ext/standard/password.c index a8aab315657c0..34eb01f322288 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -153,6 +153,12 @@ static bool php_password_bcrypt_needs_rehash(const zend_string *hash, zend_array static bool php_password_bcrypt_verify(const zend_string *password, const zend_string *hash) { int status = 0; + + /* password_hash() already rejects NUL bytes for bcrypt inputs. */ + if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) { + return false; + } + zend_string *ret = php_crypt(ZSTR_VAL(password), (int)ZSTR_LEN(password), ZSTR_VAL(hash), (int)ZSTR_LEN(hash), 1); if (!ret) { diff --git a/ext/standard/tests/password/password_bcrypt_null_verify.phpt b/ext/standard/tests/password/password_bcrypt_null_verify.phpt new file mode 100644 index 0000000000000..1ed72bd7c46fe --- /dev/null +++ b/ext/standard/tests/password/password_bcrypt_null_verify.phpt @@ -0,0 +1,14 @@ +--TEST-- +password_verify() rejects bcrypt passwords containing null bytes +--FILE-- + +--EXPECT-- +bool(true) +bool(false) +bool(false) From 512fcdb1f1d695c03e1e3e8ed6d4c8af64911fa4 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Wed, 8 Apr 2026 21:48:08 +0800 Subject: [PATCH 2/3] Update NEWS --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index d688ef5aad399..f1040eafcd834 100644 --- a/NEWS +++ b/NEWS @@ -138,6 +138,8 @@ PHP NEWS while COW violation flag is still set). (alexandre-daubois) . Added form feed (\f) in the default trimmed characters of trim(), rtrim() and ltrim(). (Weilin Du) + . Fixed bug GH-21673 Reject NUL bytes in bcrypt passwords passed to + password_verify(). (Weilin Du) . Invalid mode values now throw in array_filter() instead of being silently defaulted to 0. (Jorg Sowa) . Fixed bug GH-21058 (error_log() crashes with message_type 3 and From 08d7fcc3c7e4ad3ee11a419a6b4a7e679de34750 Mon Sep 17 00:00:00 2001 From: lamentxu <1372449351@qq.com> Date: Thu, 9 Apr 2026 15:39:28 +0800 Subject: [PATCH 3/3] Update password.c --- ext/standard/password.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ext/standard/password.c b/ext/standard/password.c index 34eb01f322288..e5ee39143e7ef 100644 --- a/ext/standard/password.c +++ b/ext/standard/password.c @@ -153,12 +153,6 @@ static bool php_password_bcrypt_needs_rehash(const zend_string *hash, zend_array static bool php_password_bcrypt_verify(const zend_string *password, const zend_string *hash) { int status = 0; - - /* password_hash() already rejects NUL bytes for bcrypt inputs. */ - if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) { - return false; - } - zend_string *ret = php_crypt(ZSTR_VAL(password), (int)ZSTR_LEN(password), ZSTR_VAL(hash), (int)ZSTR_LEN(hash), 1); if (!ret) { @@ -187,7 +181,7 @@ static zend_string* php_password_bcrypt_hash(const zend_string *password, zend_a zval *zcost; zend_long cost = PHP_PASSWORD_BCRYPT_COST; - if (memchr(ZSTR_VAL(password), '\0', ZSTR_LEN(password))) { + if (zend_str_has_nul_byte(password)) { zend_value_error("Bcrypt password must not contain null character"); return NULL; } @@ -626,6 +620,10 @@ PHP_FUNCTION(password_verify) ZEND_PARSE_PARAMETERS_END(); algo = php_password_algo_identify(hash); + if (algo == &php_password_algo_bcrypt && zend_str_has_nul_byte(password)) { + RETURN_FALSE; + } + RETURN_BOOL(algo && (!algo->verify || algo->verify(password, hash))); } /* }}} */