Login Lockdown
Version 2.0.0
July 8, 2026
Breaking (proxied sites only): client IP detection now respects Craft's trusted-proxy configuration instead of unconditionally trusting forwarding headers. If your site runs behind Cloudflare, a load balancer, or another reverse proxy, configure
trustedHosts/ipHeadersinconfig/general.php(see proxy configuration guidance) — otherwise all login attempts are attributed to the proxy's IP. Sites with direct connections are unaffected.
Security
- Fixed IP spoofing in client IP detection.
ProtectionService::getClientIp()previously trusted theCF-Connecting-IP,X-Forwarded-For, andX-Real-IPrequest headers unconditionally and used the left-most value, which is client-controlled. This let an attacker rotate a header to bypass blocking entirely, bypass the IP whitelist, or spoof a victim's IP to lock a legitimate user out of the Control Panel. IP detection now delegates to Craft'sRequest::getUserIP(), which honors forwarded headers only from proxies you've marked as trusted viatrustedHosts/ipHeadersinconfig/general.php. Sites behind Cloudflare or a reverse proxy should review the proxy configuration guidance. - Fixed a front-end login block bypass. Front-end enforcement only recognized a login when the
actionwas passed as a POST body param, so a blocked IP could keep attempting logins by targeting the/actions/users/loginpath or query-string form instead. Enforcement now inspects the resolved action, which is invariant across all invocation forms. - Bounded database writes from blocked IPs. A blocked IP that kept hitting the login endpoint previously caused one login-attempt row (plus a re-save of the block row) to be written per request, which an attacker could use to flood the database. Writes for an already-blocked IP are now throttled to at most once per 60 seconds; the 403 block is still returned on every request.
Changed
- The block response for blocked IPs is now emitted through Craft's response pipeline (via
Craft::$app->end()) instead of rawecho/exit, so framework content-type/charset handling, security-header events, and end-of-request cleanup all apply. The response contract (JSON{success, message, error}for AJAX, styled HTML otherwise,X-Login-Lockdownheader, HTTP 403) is unchanged. - Removed leftover debug logging from the Pushover test action and notification service.
Version 1.0.5
June 9, 2026
Changed
- Bumped minimum Craft CMS to
^5.9.18(was^5.8.0) so consumers no longer install Craft versions affected by GHSA-gj2p-p9m4-c8gw, GHSA-qrgm-p9w5-rrfw, and GHSA-33m5-hqp9-97pw, all patched in Craft 5.9.18 - Stopped committing
composer.lock— distributed plugins shouldn't ship lock files, since consumers resolve dependencies against their own. This also clears noise from Dependabot scans of transitive dependencies that don't actually affect consumers - Added a
.github/dependabot.ymlrestricting Composer scans to direct dependencies and only opening PRs when a new version falls outside the existing constraint, so future Dependabot activity reflects real security updates rather than lockfile churn
Version 1.0.4
March 24, 2026
Fixed
- Non-admin users with plugin access can now view the blocked IPs page without getting a 403 error
- CP nav item now hidden for users without plugin access permission
Version 1.0.3
February 4, 2026
Fixed
- Login attempts from already-blocked IPs are now recorded and reset the lockout timer
Version 1.0.2
February 2, 2026
Fixed
- Corrected GitHub repository URLs in composer.json documentation and support links
Version 1.0.1
February 2, 2026
Added
- Block expiration time now included in email and Pushover notification messages
Version 1.0.0
February 2, 2026
Added
- Brute force protection for Craft CMS control panel login
- Brute force protection for front-end login forms
- Configurable failed attempt threshold and time window
- Configurable lockout duration
- IP whitelist to exclude trusted addresses from blocking
- Email notifications when IPs are blocked
- Pushover notifications when IPs are blocked
- Control panel interface for viewing and managing blocked IPs
- CLI commands for managing blocked IPs (
login-lockdown/block/list,add,remove,check) - CLI command for cleaning up old records (
login-lockdown/cleanup) - Proxy-aware IP detection (Cloudflare, X-Forwarded-For, X-Real-IP)
- Environment variable support for all settings using
$ENV_VARsyntax