Skip to content

password_needs_rehash() returns true for security downgrades (lower cost/memory) #20801

@dg

Description

@dg

Description

The password_needs_rehash() function returns true when the new options would downgrade security (e.g., lower cost for bcrypt, lower memory_cost for argon2), which can lead to unintentional weakening of password security.

The following code:

<?php
// Create a hash with high security (cost 12)
$hash = password_hash('test', PASSWORD_BCRYPT, ['cost' => 12]);
echo "Hash created with cost 12: " . substr($hash, 0, 7) . "...\n";

// Check if rehash is needed with LOWER cost (security downgrade)
$needsRehash = password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => 5]);
echo "needsRehash (cost 12 -> 5): " . var_export($needsRehash, true) . "\n";

// This is dangerous - application might rehash to weaker security
if ($needsRehash) {
    $weakerHash = password_hash('test', PASSWORD_BCRYPT, ['cost' => 5]);
    echo "Password downgraded from cost 12 to cost 5!\n";
}

Resulted in this output:

Hash created with cost 12: $2y$12$...
needsRehash (cost 12 -> 5): true
Password downgraded from cost 12 to cost 5!

But I expected this output instead:

Hash created with cost 12: $2y$12$...
needsRehash (cost 12 -> 5): false
(no downgrade performed)

Expected behavior

password_needs_rehash() should return false when the new options would weaken security compared to the existing hash. It should only return true for:

  • Algorithm changes
  • Security upgrades (higher cost, higher memory_cost, etc.)
  • Missing/corrupted hashes

Actual behavior

The function returns true for ANY difference in options, including downgrades, which can lead to:

  1. Accidental security weakening during configuration changes
  2. Rollback/deployment issues where old config downgrades all passwords
  3. No protection against misconfiguration

PHP Version

This affects all PHP versions and all password algorithms (bcrypt, argon2i, argon2id)

Operating System

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions