Make WordPress Core

Opened 7 weeks ago

Last modified 6 weeks ago

#65144 new defect (bug)

Passwords: trim() asymmetry between wp_hash_password() and wp_check_password() introduced in 6.8

Reported by: mkultraware's profile mkultraware Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 6.8
Component: General Keywords: has-patch
Focuses: Cc:

Description

wp_hash_password() and wp_check_password() handle whitespace
inconsistently in the bcrypt path introduced in 6.8.

wp_hash_password() (pluggable.php line 2809):
hash_hmac('sha384', trim($password), 'wp-sha384', true)

wp_check_password() (pluggable.php line 2858):
hash_hmac('sha384', $password, 'wp-sha384', true)

The hashing function trims leading and trailing whitespace before
hashing. The verification function does not. This means a password
set with leading or trailing whitespace will hash as the trimmed
value but verify against the untrimmed value, producing a mismatch
and locking the user out.

The default login path (wp_authenticate) trims upstream, so normal
logins are not affected. However any code that calls wp_check_password()
directly without prior trimming is broken — this includes plugins,
REST API handlers, and custom authentication flows.

A similar issue was fixed in ticket #34889 but did not carry forward
to the new bcrypt code path added in 6.8.

Expected behavior: wp_check_password() should trim the password before
hashing for verification, mirroring wp_hash_password().

Suggested fix: change line 2858 in pluggable.php from:
hash_hmac('sha384', $password, 'wp-sha384', true)
to:
hash_hmac('sha384', trim($password), 'wp-sha384', true)

Change History (4)

#1 @hbhalodia
7 weeks ago

Hi @mkultraware, Thanks for the ticket. I can verify indeed it's an issue.

For a quick check for the usecase, we can use the below snipped as a plugin and test it out.

add_action( 'init', function() {
	$hashed   = wp_hash_password( '     password-to-hash.    ' );
	$to_check = wp_check_password( '     password-to-hash.    ', $hashed );

	var_dump( $to_check );
	wp_die();
});

The output would be bool(false), instead it should be bool(true). This is because, wp_check_password is not handling the leading/trailing spaces as how wp_hash_password does while hashing the password.

To handle is properly for all the usecases, Instead of just adding trim to line 2858, we should add the trim to all passwords IMO, but since wp_hash_password adds a unique prefix, then wp_check_password will satisfy the condition on line, 2856: elseif ( str_starts_with( $hash, '$wp' ) ) {, So for adding a patch currently, I am adding it specifically for the if condition, but we can handle that in PR review and update as needed.

Thanks,

This ticket was mentioned in PR #11675 on WordPress/wordpress-develop by @hbhalodia.


7 weeks ago
#2

  • Keywords has-patch added

Trac ticket: https://core.trac.wordpress.org/ticket/65144

  • Update function, wp_check_password, to include the trim() while checking the password created using wp_hash_password.

## Use of AI Tools

  • None

@darshitrajyaguru97 commented on PR #11675:


7 weeks ago
#3

I’ve reviewed the PR and confirmed the issue locally.

The fix looks correct for the bcrypt ($wp) path and aligns with wp_hash_password() behavior.

A couple of points to consider:

  1. The PR description could include more context about the mismatch and its impact on direct wp_check_password() usage.
  2. Are there PHPUnit tests covering leading/trailing whitespace cases? Adding those would help prevent regressions.
  3. CI checks appear incomplete (PHPUnit cancelled). It may be worth ensuring all tests pass before review.

Also, should trimming be limited to the $wp path only, or applied consistently across all password verification paths?

#4 @ankitv
6 weeks ago

The asymmetry is in the bcrypt path only. wp_hash_password()
calls trim() before hash_hmac() but wp_check_password() does not,
causing login failures for passwords with leading/trailing
whitespace when wp_check_password() is called directly.

Fix: add trim() to the password argument in wp_check_password()
to match wp_hash_password().

Patch submitted via PR: https://github.com/Anny0007/AV-wordpress-develop/pull/2

Please update keywords to has-patch.

Note: See TracTickets for help on using tickets.