# Block Passwords Found in Known Data Breaches

> Checks new passwords against the Have I Been Pwned database of breached passwords when users change or reset them, and asks for a different one if it appears there.

- Type: PHP
- Runs: Run everywhere
- Category: [Security](https://wpide.com/library/category/security/)
- Tags: passwords, breaches, policy
- Author: WPIDE Team
- Installs: 0
- Updated: 2026-10-28
- Page: https://wpide.com/library/sec-breached-password-check/

## Code

```php
$wpide_breach_count = function ( $password ) {
    $hash   = strtoupper( sha1( (string) $password ) );
    $prefix = substr( $hash, 0, 5 );
    $cache  = 'wpide_hibp_' . $prefix;
    $body   = get_transient( $cache );

    if ( false === $body ) {
        $response = wp_remote_get( 'https://api.pwnedpasswords.com/range/' . $prefix, array(
            'timeout' => 4,
            'headers' => array( 'Add-Padding' => 'true', 'User-Agent' => 'WordPress password check' ),
        ) );
        if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
            return 0;
        }
        $body = wp_remote_retrieve_body( $response );
        set_transient( $cache, $body, 12 * HOUR_IN_SECONDS );
    }

    if ( preg_match( '/^' . substr( $hash, 5 ) . ':(\d+)/m', $body, $m ) ) {
        return (int) $m[1];
    }

    return 0;
};

$wpide_breach_message = 'This password has appeared in a data breach and is unsafe. Please choose a different one.';

add_action( 'user_profile_update_errors', function ( $errors, $update, $user ) use ( $wpide_breach_count, $wpide_breach_message ) {
    if ( ! empty( $user->user_pass ) && $wpide_breach_count( $user->user_pass ) > 0 ) {
        $errors->add( 'wpide_pwned', '<strong>Error:</strong> ' . $wpide_breach_message );
    }
}, 10, 3 );

add_action( 'validate_password_reset', function ( $errors ) use ( $wpide_breach_count, $wpide_breach_message ) {
    $pass = isset( $_POST['pass1'] ) ? (string) wp_unslash( $_POST['pass1'] ) : '';
    if ( $pass && $wpide_breach_count( $pass ) > 0 ) {
        $errors->add( 'wpide_pwned', $wpide_breach_message );
    }
} );
```

## Notes

Only the first 5 characters of the password's SHA-1 hash are sent (k-anonymity), never the password; if the service cannot be reached, the password is allowed.

## How to use it

Install the free WPIDE plugin (https://wordpress.org/plugins/wpide/), find "Block Passwords Found in Known Data Breaches" in its snippet library and add it in one click; or create a new PHP snippet in WPIDE (or any code snippets plugin) and paste the code above. More snippets: https://wpide.com/library/
