What’s the problem?
In this article, we’ll cover a security issue with the WordPress password recovery form. You can access this form from the WP login page by clicking the Lost your password? link.

The form lets users who forgot their password restore access by receiving a special recovery link after entering their email or username.
So what’s the problem? If a user enters an email/username that doesn’t exist, WordPress shows an error message saying that no such user exists. This is a potential security risk because attackers can use it to enumerate valid usernames or emails.

The solution: Return the same message whether the email/username is correct or not. If the user enters a valid address, they’ll still receive the recovery email. If not, nothing is sent - but the on-screen response looks identical. Below we’ll show how to implement this.
Additional issue: REST endpoint
By default, WordPress exposes a REST endpoint that can list registered users and their data.
Open the following path on your site:
/wp-json/wp/v2/users/
It will return JSON with user data.

This is also a serious security concern. In the next section, we’ll cover how to close it.
How to fix it
Many WordPress security plugins can harden the password recovery form and lock down REST endpoints. In this article, we’ll show how to do it with simple PHP code snippets.
Using small custom code avoids bloating your site with unnecessary features. You don’t need a large plugin that may slow your site down or introduce new vulnerabilities.
Add the following snippet:
class Protect_WP_Pass_Reset_Form{
private $send_email = true;
public function __construct() {
add_filter( 'lostpassword_errors', array( $this, 'lostpassword_errors' ) );
add_filter( 'lostpassword_user_data', array( $this, 'lostpassword_user_data' ) );
add_filter( 'send_retrieve_password_email', array( $this, 'send_retrieve_password_email' ) );
add_filter( 'rest_endpoints', array( $this, 'rest_endpoints' ) );
}
/*
* Remove errors related to incorrect email
*/
public function lostpassword_errors( $errors ) {
if ( $errors && $errors->has_errors() ) {
if ( isset( $errors->errors['invalid_email'] ) ) {
$errors->remove('invalid_email');
$this->send_email = false;
}
if ( isset( $errors->errors['invalidcombo'] ) ) {
$errors->remove('invalidcombo');
$this->send_email = false;
}
}
return $errors;
}
/*
* Fix error with empty users data when invalid login/email
*/
public function lostpassword_user_data( $user_data ) {
if ( ! $user_data ) {
$user_data = true;
$this->send_email = false;
}
return $user_data;
}
/*
* Deside send recovery email or not
*/
public function send_retrieve_password_email( $send ) {
if ( ! $this->send_email ) {
return false;
}
return $send;
}
/*
* Remove rest enpoits
*/
public function rest_endpoints( $endpoints ) {
unset($endpoints['/wp/v2/users'], $endpoints['/wp/v2/users/(?P<id>[\d]+)']);
return $endpoints;
}
}
new Protect_WP_Pass_Reset_Form();
Add this code to your child theme’s functions.php file or use a code-snippets plugin.
Results
With this small snippet, the WordPress password recovery form no longer reveals whether an email/username exists. It always shows the same on-screen message.
If an email/username doesn’t exist, no recovery email is sent.
If an email/username exists, the recovery email is sent as usual.


Additionally, the users REST endpoint is disabled, so it no longer returns user data in JSON.
