WP Manifestindependent plugin directory
manifest / security / lostpassword-hardening

Lost Password Hardening

Hardens the WordPress "Lost Password" page against bots and account enumeration — adds rate limiting, a honeypot field, and generic error responses.

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/john-mark-bondad/lostpassword-hardening/archive/refs/heads/master.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

A lightweight WordPress plugin that hardens the default wp-login.php?action=lostpassword page against bots and brute-force / account-enumeration attacks — without requiring a full security suite.

Why

The default WordPress "Lost Password" page has a few weaknesses out of the box:

  • It reveals whether a username or email exists on the site (account enumeration).
  • It has no rate limiting, so bots can submit the form thousands of times per minute.
  • It has no bot filtering (CAPTCHA, honeypot, etc.).
  • Failed/suspicious attempts aren't logged anywhere.

This plugin patches those gaps using WordPress core hooks only — no external dependencies, no API keys required.

Features

  • Rate limiting — throttles repeated password reset attempts per IP address (default: 3 attempts per 15 minutes).
  • Honeypot field — adds an invisible field to the form that only bots fill in; real visitors never see it.
  • Generic responses — always shows the same message ("If an account exists...") regardless of whether the username/email is valid, so attackers can't use the form to discover real accounts.
  • Request logging — logs reset requests, rate-limit hits, and honeypot triggers (with IP and timestamp) to your PHP error log for monitoring.
  • Shorter reset link lifetime — reduces the password reset link validity window from the WordPress default of 24 hours down to 12 hours.
  • Fail-safe error handling — every custom check is wrapped in try/catch, so a failure in this plugin logs an error instead of breaking the password reset flow for legitimate users.

Installation

Option A — Regular plugin (recommended for most sites)

  1. Download the latest release or clone this repo.
  2. Zip the lostpassword-hardening folder (or use the provided .zip).
  3. In wp-admin, go to Plugins → Add New → Upload Plugin and upload the zip.
  4. Click Activate.

Option B — Must-use plugin (always-on, can't be accidentally deactivated)

  1. Copy just lostpassword-hardening.php (not the folder) into wp-content/mu-plugins/.
  2. Create the mu-plugins folder if it doesn't already exist.
  3. That's it — mu-plugins load automatically, no activation step needed.

Note: mu-plugins don't support subfolders being auto-loaded, so this file must sit loose directly inside mu-plugins/, not inside its own directory.

Verifying it works

  • Submit the lost password form more than 3 times in a row from the same IP — you should see "Too many password reset attempts" on the 4th try.
  • Check your PHP error log (or wp-content/debug.log if WP_DEBUG_LOG is enabled in wp-config.php) for entries prefixed with [LostPassword].

Configuration

All settings are constants inside lostpassword-hardening.php:

Setting Location Default
Max attempts before throttling Section 1 ($max_attempts) 3
Throttle window Section 1 ($window_seconds) 15 minutes
Reset link expiration Section 5 (password_reset_expiration filter) 12 hours

Edit these values directly in the file to adjust thresholds.

This plugin covers the application-level gaps in the lost password flow. For a fuller security posture, consider pairing it with:

  • A WAF or IP-level rate limiter (Cloudflare, Wordfence, Sucuri) in front of wp-login.php.
  • CAPTCHA (reCAPTCHA v3 / hCaptcha) on the login and lost-password forms.
  • Two-factor authentication for all user accounts.
  • Disabling XML-RPC if you don't need it.

License

GPL-2.0-or-later — see LICENSE or https://www.gnu.org/licenses/gpl-2.0.html

Author

John Mark Bondad GitHub