Brute Force Protection

Lock out IPs after repeated failed login attempts.

LoginPlus tracks failed login attempts per IP address and username together. When that pair exceeds the configured threshold within the lockout window, further attempts using that username from that IP are blocked until the window expires.

Configuration

Go to LoginPlus → Settings → Brute Force to adjust:

OptionDefaultDescription
Enable brute force protectionOn (from activation)Toggles the feature globally
Max attempts5Failed logins before lockout triggers
Lockout duration15 minutesHow long the IP+username pair is blocked
IP allowlistEmptyOne IP per line (IPv4 or IPv6) that’s never locked out, no matter how many failures

How it works

  • Hooks the authenticate filter (checked before and after WordPress’s own credential check) to reject login for a locked-out IP+username pair, plus wp_login_failed to record a miss and wp_login to reset the counter on success.
  • Uses WordPress transients keyed by a hash of the IP and the lowercased username — not a separate database table.
  • After lockout, returns a WP_Error that prevents WordPress from progressing the login.
  • A successful login resets the failed-attempt counter for that IP+username pair.
  • The 2FA code-entry step is rate-limited the same way: if it’s ever submitted without a username (e.g. a raw HTTP replay of a captured session), attempts are bucketed by the 2FA token instead, so the 6-digit code can’t be brute-forced by skipping the username field.

Detecting the real IP behind a proxy or CDN

LoginPlus checks these in order and uses the first valid IP it finds:

  • CF-Connecting-IP (Cloudflare)
  • X-Real-IP
  • REMOTE_ADDR (the direct connecting IP)

X-Forwarded-For is deliberately not used — on a server without a properly validated reverse proxy, that header can be set by the client itself and used to spoof an IP to dodge a lockout.

Clearing a lockout manually

The lockout key includes an MD5 hash of the IP, so it can’t be typed by hand. Clear it with wp eval instead:

wp eval 'delete_transient( "lp_attempts_" . md5( "203.0.113.42" ) . "_" . strtolower( "the-username" ) );'

Replace the IP and username with the locked pair’s actual values. Alternatively, add the IP to the allowlist above if it belongs to a trusted admin or office.