=== Login Armor ===
Contributors: wpformation
Donate link: https://wpformation.com
Tags: login security, hide login, brute force, limit login, activity log
Requires at least: 6.8
Tested up to: 7.0
Stable tag: 2.4.6
Requires PHP: 8.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Twelve security modules + AI briefing: hide login, request firewall, brute force, 2FA, password policy, sessions, hardening, audit log. No upsells.

== Description ==

🇫🇷 **Fully translated into French. Interface et documentation intégralement disponibles en français.**

**Twelve security modules. One lightweight plugin. No premium tier.**

Login Armor protects WordPress login, accounts and administration with twelve independent modules. It is built for agencies, freelancers and site owners who want practical security, clear evidence and safe defaults without a remote dashboard, bundled telemetry or upsells.

= Why Login Armor =

* **Complete and free:** every module is included under the GPL.
* **Lightweight:** modules load only when needed and normal login checks add less than 2 ms on a typical setup.
* **Private by default:** data stays on your site. Optional external calls are disabled until you enable the related feature.
* **Ready for real sites:** multisite support, reverse-proxy controls, WP-CLI commands and production-safe defaults.

= Twelve security modules =

1. **Hide Login:** replace `wp-login.php` with a private slug and return a 404 or redirect blocked visitors to a chosen URL.
2. **Brute Force Protection:** escalating lockouts, subnet blocking, trusted proxy headers and coverage for login, password recovery, registration, XML-RPC and REST users.
3. **Hardening:** fifteen controls for XML-RPC, pingbacks, file editing, version exposure, application passwords, author enumeration, reserved usernames, honeypots and new-admin alerts.
4. **Two-Factor Authentication:** TOTP, email codes, backup codes, trusted devices, per-role enforcement, grace periods and recovery.
5. **Detection and Incidents:** group raw events into attack patterns with severity, timelines, source IPs, targeted users and one-click actions.
6. **Activity Log:** tamper-evident admin audit trail with filters, CSV export, retention controls and optional signed SIEM forwarding.
7. **Security Headers:** CSP, X-Frame-Options, Permissions-Policy, Referrer-Policy and X-Content-Type-Options for login and lockout pages, with optional site-wide baseline headers.
8. **Breach Check:** privacy-preserving Have I Been Pwned password checks and an optional XposedOrNot email check.
9. **Password Policy:** length and character rules, username exclusion, breached-password rejection and optional non-locking expiration reminders.
10. **Session Management:** idle timeout, maximum lifetime, optional single-device access and one-click revocation of other sessions.
11. **IP Geolocation:** cached country lookup for IPs shown in Incidents and Events, with private ranges excluded.
12. **Request Firewall:** optional, monitor-first filtering of malicious paths, query strings and HTTP methods, with administrator exclusions and IP/path allowlists.

= Additional tools =

Login Armor also includes guided onboarding, a 0-100 security score, conflict detection, email/Slack/Discord/webhook notifications, a dashboard widget and a complete WP-CLI suite.

The optional AI Security Briefing uses your own WordPress AI connector to explain a thirty-day security snapshot or a single incident. It always starts with deterministic facts, works without AI and sends nothing until an administrator explicitly requests an analysis.

GPL forever. PHP 8.1+. WordPress 6.8+. Zero dependencies.

---

**Douze modules de sécurité. Une seule extension légère. Aucune version premium.**

Login Armor protège la connexion, les comptes et l'administration de WordPress grâce à douze modules indépendants. L'extension s'adresse aux agences, freelances et propriétaires de sites qui veulent une sécurité concrète, des preuves lisibles et des réglages sûrs, sans tableau de bord distant, télémétrie imposée ni upsell.

= Pourquoi Login Armor =

* **Complet et gratuit :** tous les modules sont inclus sous licence GPL.
* **Léger :** les modules se chargent uniquement lorsque nécessaire et les contrôles ajoutent moins de 2 ms sur une connexion normale.
* **Privé par défaut :** les données restent sur votre site. Les appels externes optionnels sont désactivés tant que vous n'activez pas la fonction concernée.
* **Prêt pour la production :** multisite, reverse proxies, commandes WP-CLI et réglages par défaut sécurisés.

= Douze modules de sécurité =

1. **Masquer la connexion :** remplace `wp-login.php` par un slug privé et renvoie une 404 ou redirige les visiteurs bloqués vers l'URL choisie.
2. **Protection contre la force brute :** verrouillages progressifs, blocage de sous-réseaux, proxies de confiance et protection de la connexion, récupération, inscription, XML-RPC et REST users.
3. **Renforcement :** quinze contrôles pour XML-RPC, les pingbacks, l'éditeur de fichiers, la version, les mots de passe applicatifs, l'énumération d'auteurs, les identifiants réservés, le pot de miel et les alertes nouvel administrateur.
4. **Authentification à deux facteurs :** TOTP, codes par e-mail, codes de secours, appareils de confiance, application par rôle, période de grâce et récupération.
5. **Détection et incidents :** regroupe les événements en scénarios d'attaque avec sévérité, chronologie, IP sources, comptes ciblés et actions immédiates.
6. **Journal d'activité :** piste d'audit admin infalsifiable avec filtres, export CSV, rétention et transfert SIEM signé optionnel.
7. **En-têtes de sécurité :** CSP, X-Frame-Options, Permissions-Policy, Referrer-Policy et X-Content-Type-Options pour les pages de connexion et de verrouillage, avec en-têtes de base optionnels sur tout le site.
8. **Détection de fuites :** vérification confidentielle des mots de passe via Have I Been Pwned et contrôle optionnel des e-mails via XposedOrNot.
9. **Politique de mot de passe :** longueur, classes de caractères, exclusion de l'identifiant, rejet des mots de passe compromis et rappels d'expiration non bloquants.
10. **Gestion des sessions :** délai d'inactivité, durée maximale, accès limité à un appareil et révocation des autres sessions.
11. **Géolocalisation IP :** pays des IP affichées dans Incidents et Événements, avec cache et exclusion des plages privées.
12. **Pare-feu de requêtes :** filtrage optionnel, d'abord en surveillance, des chemins, requêtes et méthodes HTTP malveillants, avec exclusion des administrateurs et listes d'autorisation IP/chemins.

= Outils complémentaires =

Login Armor inclut aussi un assistant de configuration, un score de sécurité de 0 à 100, la détection de conflits, les notifications par e-mail, Slack, Discord ou webhook, un widget de tableau de bord et une suite WP-CLI complète.

Le briefing de sécurité IA optionnel utilise votre propre connecteur IA WordPress pour expliquer les trente derniers jours ou un incident précis. Il commence toujours par des faits déterministes, fonctionne sans IA et n'envoie rien tant qu'un administrateur ne demande pas explicitement une analyse.

= Conçu par =

Login Armor est conçu et maintenu par Fabrice Ducarme de [WPFormation](https://wpformation.com/login-armor/). Nous l'utilisons sur chaque site que nous livrons.

* [Présentation et fonctionnement de Login Armor](https://wpformation.com/login-armor/)
* [Guides de sécurité WordPress](https://wpformation.com/securite-wordpress/) sur WPFormation
* [Veille des vulnérabilités WordPress](https://wpformation.com/outils/veille-securite/) sur WPFormation

GPL pour toujours. PHP 8.1+. WordPress 6.8+. Zéro dépendance.

== Installation ==

1. Upload the `login-armor` directory to `/wp-content/plugins/`
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Go to LoginArmor in the admin menu to configure

For multisite: Network Activate the plugin to apply it across all sites.

= Setting up Hide Login =

1. Go to LoginArmor > Settings > Hide Login section
2. Enter your desired login slug (e.g., `my-login`)
3. Save settings
4. **Bookmark your new login URL**: you will need it to access your admin

= Recovering access =

If you forget your custom login URL:

* Use the recovery email feature (configurable in settings)
* Connect to your database and delete the `login_armor_hide_slug` row from the `wp_options` table
* Use WP-CLI: `wp option delete login_armor_hide_slug`

== Frequently Asked Questions ==

= Will it lock me out of my own site? =

No. Hide Login always sends a one-time recovery URL to the admin email. If you lose the slug, check your inbox. The plugin also honors `wp-cli` fallback so you can reset anything from SSH.

= Does it slow my site down? =

No. Everything is lazy-loaded and indexed. On a normal login flow the extra SQL cost is under 2 ms.

= Is it compatible with Cloudflare / reverse proxies? =

Yes. IP detection honors trusted `X-Forwarded-For` headers; you pick the header in Settings.

= Does it work with multisite? =

Yes, subdomain and subfolder. Each site has its own modules, logs, and thresholds.

= Can I use LoginArmor alongside Wordfence / iThemes Security / Solid Security? =

Yes, but disable overlapping modules on one side to avoid double lockouts.

= Where is the data stored? =

Three custom tables in your own database: events, incidents, activity. Nothing leaves your server.

= How do I migrate my configuration? =

Settings are plain WordPress options. Export/import via WP-CLI or any standard options-sync tool.

= Is there a pro version? =

Not currently. LoginArmor is fully free and open source. GPL forever.

= Where can I report bugs or request features? =

Support forum: [wordpress.org/support/plugin/login-armor/](https://wordpress.org/support/plugin/login-armor/).

== Screenshots ==

1. Quick tour of all eight modules - Hide Login, Hardening, 2FA setup with QR code, Incidents drill-down, Activity Log, Events, and Overview dashboard.
2. Overview dashboard - health cards, security pulse, live event tail, threat banner that surfaces active attacks.
3. Incidents - real-time pattern detection grouped by attack class with severity and one-click resolution.
4. Incident drill-down - full timeline, user-agent fingerprint, suggested actions, escalation flag.
5. Events - complete login attempts log with filters and CSV export.
6. Activity Log - admin action audit trail across seven domains, filterable and exportable.
7. Settings - modular configuration with live security score and a sticky save bar.
8. Hide Login pre-activation modal - pick or generate the secret URL and email it to yourself before flipping the switch.
9. Hardening - thirteen one-click toggles grouped by surface reduction, credential hardening, and request filtering.
10. Two-factor authentication setup - QR code for any authenticator app, copy-paste fallback, and live verification.
11. Breach Check - fully transparent k-anonymity lookups, separate password and email toggles, opt-in email check disabled by default.

== External Services ==

Login Armor has no telemetry and requires no Login Armor account. The following services are contacted only when WordPress itself or an administrator enables the related feature.

= WordPress AI connector (optional) =

The AI Security Briefing sends a security prompt through the administrator's own WordPress AI connector only after they click an analysis button. Minimised mode sends counts, categories, severities and role buckets without clear IP addresses or usernames. Explicit deep mode also sends IP addresses and event details. Login Armor stores no provider API key. The selected AI provider's terms and privacy policy apply.

= Slack, Discord or custom webhook (optional) =

When an administrator enables an incident notification channel, Login Armor sends the incident type, severity, IP address, target username, event count and site URL to the configured endpoint. The separate signed Activity Log forwarding option sends the event, object, user ID/login/role, IP address, description, integrity hashes, site URL and plugin version to the administrator's SIEM or custom webhook.

* **Slack:** [Terms](https://slack.com/terms-of-service) | [Privacy](https://slack.com/privacy-policy)
* **Discord:** [Terms](https://discord.com/terms) | [Privacy](https://discord.com/privacy)
* **Custom webhook:** terms and privacy are controlled by the administrator's chosen endpoint.

= Gravatar =

The Activity Log uses WordPress core's `get_avatar()`. If avatars are enabled in WordPress, a hashed email address may be sent to Gravatar to retrieve the image.

* **Gravatar:** [Terms](https://automattic.com/tos/) | [Privacy](https://automattic.com/privacy/)

= Have I Been Pwned (optional) =

Breach Check and the optional compromised-password policy send only the first 5 characters of a password's SHA-1 hash to the Pwned Passwords API. The password and full hash never leave the site. Checks fail soft if the service is unavailable.

* **Have I Been Pwned:** [Privacy](https://haveibeenpwned.com/Privacy) | [Acceptable Use](https://haveibeenpwned.com/AcceptableUse)

= XposedOrNot (optional) =

The separate Email check, disabled by default, sends the user's email address and a plugin-identifying User-Agent to XposedOrNot when a user is created or changes email.

* **XposedOrNot:** [Service](https://xposedornot.com/) | [Privacy](https://xposedornot.com/privacy.html)

= ipwho.is (optional) =

IP Geolocation sends a displayed public IP address to ipwho.is when an administrator opens Incidents or Events. Results are cached for 30 days. Private and reserved ranges are never sent, and developers can replace the lookup through the `login_armor_geoip_lookup` filter.

* **ipwho.is:** [Service](https://ipwho.is/) | [Documentation](https://ipwhois.io/documentation)

== Changelog ==

= 2.4.6 =
Hide Login correction from a user report. The custom blocked-access redirect now works for both `/wp-admin/` and `/wp-login.php`. FSE 404 templates reached through `/wp-admin/` now load the public block styles required by navigation and other core blocks. Legacy redirect values remain compatible.

= 2.4.5 =
Accuracy release from a user report. Login Armor's own blocks no longer count as failed passwords: a two-factor lockout, a two-factor rate limit, the mandatory-2FA gate, a honeypot catch and a reserved-username rejection each used to insert a brute-force attempt on top of their own sanction, so one mistyped 2FA code could push a legitimate user into the IP lockout while signing in with the correct password. Failed logins now record the real reason instead of always reporting "Wrong password": the Events tab, the incident timeline, the Overview live tail and the CSV export distinguish a wrong password from an unknown account, cookies blocked by the browser, each of the plugin's own gates, and a refusal coming from another plugin (shown with its code). Existing log rows keep the previous label. Also fixes a separate bug found while testing this release: the incidents table failed to create on MariaDB 11.7+/MySQL 9 because the `vector` column collided with a new reserved word, which silently disabled the whole Detection engine on those servers.

= 2.4.4 =
Hardening release from an external code audit; five confirmed issues fixed and each verified end-to-end (real HTTP flow locally, re-run under PHP 8.4, and validated on a live WordPress 7.0 / PHP 8.3 install). The Overview dashboard now computes the threat level and active-incident count over every active incident, so an older critical incident can no longer drop the headline back to "Normal". A successful two-factor login now fires the canonical wp_login cycle, so failed-attempt counters reset, the login is logged, the single-session policy applies and third-party integrations run. Lockout escalation is now atomic under concurrency, so a burst of simultaneous failures can no longer turn a first offence into an immediate long ban. The Slack/Discord/generic notification webhooks are re-validated against private, reserved, link-local and IPv6-internal addresses before every send (SSRF), and CSV log exports neutralise spreadsheet formula injection from attacker-controlled fields. Plugin Check 0 ERROR.

= 2.4.3 =
Security release. Mandatory two-factor authentication is now a hard gate: a user in an enforced role who never enrolled and whose grace period has expired is blocked at login instead of being let in with only a redirect to their profile (reported by the WordPress Plugin Review Team). Existing users are never locked out unexpectedly - the grace window is started automatically the first time enforcement applies, and an admin can reopen it from the Users list ("Restart 2FA grace") or via WP-CLI. Hardened: TOTP codes can no longer be replayed within their validity window (single-use per time-step, RFC 6238); the Activity Log webhook URL is validated against private, reserved, link-local and IPv6-internal addresses (SSRF), matching the notification channels; attacker-submitted usernames are neutralised before entering the optional AI incident prompt. A filter (login_armor_2fa_hard_enforcement) restores the previous soft behaviour if needed.

= 2.4.2 =
Coherence and lifecycle release. Fixes: deactivation now clears every scheduled task (three were left running); uninstall removes all options, user meta and caches from the newer modules (AI, Password Policy, Sessions, GeoIP, Firewall); disabling Two-Factor now asks for confirmation like every other module; the plugin's own conflict warnings, silently hidden since 2.4.0, show again. Improvements: a composite database index speeds up brute-force lookups, open incidents are capped so the table cannot grow forever, and the admin UI is more consistent (numeric fields, empty states, module counters). New: a warning when a front-end login plugin such as Ultimate Member is active, since Two-Factor and Hide Login are not compatible with a front-end login form. No behaviour change on standard installs.

= 2.4.1 =
Fix: a "critical error" could occur during password recovery when another active plugin re-fires a WordPress core hook with an off-contract argument type or arity (for example a null passed to retrieve_password_message ahead of Login Armor). Strict parameter hints are relaxed, each with an internal type guard, on every core-hook callback across all modules; behaviour is unchanged on canonical WordPress calls. Generalises the 2.1.15 URL-builder fix to the whole plugin.

= 2.4.0 =
Feature release - request firewall, guided onboarding, fuller in-app docs.

* New - **Request Firewall** (optional, off by default): a PHP "8G"-style filter that blocks malicious query strings, paths and HTTP methods before WordPress fully loads (Apache/Nginx/LiteSpeed/IIS). Starts in monitor mode; admins, REST, cron, WP-CLI and admin-ajax are never filtered; IP/path allowlist (CIDR); blocks aggregate to one incident per IP per hour.
* New - **Onboarding wizard** with a one-click safe baseline (Simple) or manual setup (Advanced), plus a permanent "Apply safe baseline" button. Upgrading sites see no change.
* Improvement - Granular security-plugin conflict warnings, a cache-plugin warning when Hide Login is on, and contextual help for the modules added since 2.2.0.

= 2.3.0 =
Feature release - account-security hardening.

* New - **Password Policy**: minimum length and character-class rules, forbid the username in the password, optionally reject breached passwords (privacy-preserving HIBP), optional non-locking expiration.
* New - **Session Management**: idle timeout, maximum session lifetime, optional single active device, and "sign out all other devices".
* New - **IP Geolocation** (opt-in): country next to IPs on Incidents/Events; lazy, cached, private ranges never sent (see External Services).
* Improvement - Score now accounts for Password Policy and Session Management; baseline headers can apply site-wide; every IP lockout creates an incident. New hardening: disable pingbacks, alert on new admin.

= 2.2.0 =
Feature release - the AI Security Briefing.

* New - **AI Security Briefing** on the Overview: one click turns your last 30 days of activity into a plain-language verdict, an IP picture and prioritised actions. Built on the WordPress 7 native AI Client - uses your own connector, stores no API key, runs only on click. Always leads with a deterministic facts snapshot (with or without AI); plus "Explain with AI" on an incident.
* Privacy - Minimised mode (anonymised signals) is the default; deep mode (real IPs) is an explicit opt-in. See External Services.

= 2.1.26 =
Fix: email/backup 2FA bouncing to "session expired" on browsers that don't return the verification cookie; the form now also carries the session token. Security unchanged.

= 2.1.25 =
Fix: email/backup two-factor verification rejected in some browsers (notably Chrome); the form is now uncached and authenticated by the signed same-site cookie.

= 2.1.24 =
Fix: fatal error during authenticator-app setup on hosts whose wp-config.php does not define AUTH_KEY (e.g. some Infomaniak installs). Existing setups unaffected.

= 2.1.23 =
Fix: 2FA login screen - "use a different method" links now work, expired/locked sessions explain themselves, and the setup button reports errors.

= 2.1.22 =
Fix: the Security Score now counts default-on modules (Brute Force, Detection). Display and scoring only.

= 2.1.21 =
Cleaner user-agent labels in the Events table.

= 2.1.20 =
Migration-aware Activity Log integrity (amber "Keys changed" instead of a false TAMPERED alarm), an XML-RPC blind-spot warning, and a complete French translation.

= 2.1.19 =
Clearer attack-type labels on incidents, translatable admin toasts, French translation of the visible tabs, and an integrity-badge verify fix.

= 2.1.18 =
Fix: bulk actions now work when incidents are all resolved; the attack-vector pill shows only for XML-RPC/REST.

= 2.1.17 =
Incidents now record and show the attack vector (XML-RPC / REST / login form) and support bulk resolve/ignore.

= 2.1.16 =
Plain-permalink fixes (Hide Login URL, REST allowlist), activity-log coverage for 2FA/registration/reset, and Honeypot on WooCommerce and frontend forms.

= 2.1.15 =
Fix: fatal TypeError when plugins (e.g. WP Fastest Cache) call WordPress URL builders with off-contract argument types.

= 2.1.14 =
Fix: the prevent_author_enum toggle no longer blocks the legitimate ?author=N filter in the wp-admin Posts/Pages lists.

= 2.1.13 =
Fix: silent 2FA failure on non-trailing-slash permalinks (e.g. /%postname%) - the verify cookie path mismatched the request path.

= 2.1.12 and earlier =
Bug fixes, security hardening and i18n across the 2.1.x and 2.0.x series (Hide Login host-awareness, CSP, lockout delivery, REST scope, IPv6, HTTP/2, Activity Log integrity), through the initial 2.0.0 release. Full per-version notes: CHANGELOG.md in the plugin folder.

== Upgrade Notice ==

= 2.4.6 =
Fixes the Hide Login custom redirect and restores FSE block styles on protected 404 responses.

= 2.4.5 =
The plugin's own blocks (2FA lockout, honeypot, reserved username) no longer count as failed passwords, so a legitimate user is not locked out while using the correct one. Failed logins now show their real reason. Also fixes the incidents table failing to create on MariaDB 11.7+/MySQL 9.

= 2.4.4 =
Hardening release: the dashboard threat level no longer under-reports an older critical incident, two-factor logins now fire the canonical wp_login cycle (attempt reset, logging, single-session), lockout escalation is atomic under concurrency, notification webhooks are re-validated against SSRF before every send, and CSV exports neutralise formula injection. Verified locally and on a live WordPress 7.0 / PHP 8.3 install. Recommended for all installs.

= 2.4.3 =
Security fix: mandatory 2FA is now actually enforced at login for enrolled roles past their grace period (reported by the WordPress Plugin Review Team), without locking out existing users - an admin can reopen the setup window from the Users list. Also blocks TOTP code replay, tightens webhook SSRF checks, and neutralises AI-prompt input. Recommended for all installs.

= 2.4.2 =
Coherence release: cleaner deactivation and uninstall, a confirmation before disabling Two-Factor, faster brute-force lookups, and a heads-up when a front-end login plugin (e.g. Ultimate Member) is active. No behaviour change on standard installs. Recommended for all.

= 2.4.1 =
Fixes a "critical error" during password recovery when another plugin re-fires a WordPress hook with an off-contract argument type. Strict parameter hints relaxed, with internal guards, on every core-hook callback plugin-wide. Neutral on standard calls. Recommended for all installs.

= 2.4.0 =
New: an optional Request Firewall (8G-inspired PHP filter) that blocks malicious requests - off by default, starts in monitor mode (logs without blocking), admins never filtered. Plus a first-run onboarding wizard with a one-click safe baseline. All opt-in; existing sites unchanged.

= 2.3.0 =
Account-security release: Password Policy (length/complexity + reject breached passwords via privacy-preserving HIBP), Session Management (idle timeout, max lifetime, single session), and opt-in IP Geolocation. All off by default; nothing changes until you enable it.

= 2.2.0 =
New: the AI Security Briefing turns your last 30 days of activity into a plain-language verdict, an IP picture and prioritised actions, on top of a deterministic facts snapshot. Built on the WordPress 7 native AI Client - uses your own connector, no API key stored, runs on click.

= 2.1.26 =
Fixes email/backup 2FA bouncing to "session expired" on browsers that don't return the verification cookie on submit (some Chrome setups; Firefox worked). The form now also carries the session token, so login works regardless. Recommended if Email 2FA is enabled. Security unchanged.

= 2.1.25 =
Fixes email/backup two-factor verification being rejected ("session expired") in some browsers, notably Chrome, while Firefox worked. The form is now uncached and authenticated by the signed same-site cookie. Recommended if Email 2FA is enabled.

= 2.1.24 =
Fixes a fatal error (HTTP 500 / "network error") during authenticator-app (TOTP) setup on hosts whose wp-config.php does not define AUTH_KEY, such as some Infomaniak installs. Recommended if Two-Factor is enabled. Existing setups are unaffected.

= 2.1.23 =
Fixes the two-factor login screen: the "use a different method" links now work (and email a fresh code when switching to Email), expired/locked sessions explain themselves, and the authenticator-setup button reports errors. Recommended for 2FA users.

= 2.1.22 =
Fixes a Security Score that under-counted active modules: Brute Force and Detection (on by default) are now scored correctly, so the header, the score number and the module list agree. Display and scoring only — recommended for all installs.

= 2.1.21 =
Cosmetic patch: cleaner user-agent labels in the Events table — Jetpack/WordPress.com clients are recognised, and long agents are trimmed at a word boundary with an ellipsis instead of a chopped-off string with a dangling parenthesis.

= 2.1.20 =
Migration-friendly integrity: a security-key change now shows an amber "Keys changed" advisory with one-click chain re-baseline instead of a false "TAMPERED" alarm. Adds an XML-RPC blind-spot warning when Hide Login is on but XML-RPC stays open. Completes the French translation.

= 2.1.19 =
Clearer attack-type labels + descriptions on incidents, French translation of the visible admin tabs, translatable toast notifications, and a fix for the Activity Log integrity badge staying "UNVERIFIED" after a successful verify. Recommended for all installs.

= 2.1.18 =
Patch. Fixes "Select all" / bulk actions when incidents are all resolved (checkboxes now on every card) and only labels the attack vector for XML-RPC/REST (no more misleading "via login form"). Recommended for 2.1.17 users.

= 2.1.17 =
Feature release. Incidents now show the attack vector (XML-RPC / REST / login form) — spot which attempts bypass your hidden login URL — plus bulk mark-resolved/ignore. Adds a vector column to the incidents table (auto migration). Recommended for all installs.

= 2.1.16 =
Bug fix release from an external audit. Fixes plain-permalinks compat (Hide Login URL, REST API allowlist), restores activity-log coverage for 2FA, frontend registration and password reset, and extends Honeypot to WooCommerce + frontend login forms. Recommended for all installs.

= 2.1.15 =
Fixes a fatal TypeError when third-party plugins (e.g. WP Fastest Cache) call WordPress URL builders with off-contract argument types. Strict parameter hints relaxed on seven callbacks; return types unchanged. Neutral on canonical WP calls.

= 2.1.14 =
Bug fix. The prevent_author_enum hardening toggle no longer blocks the legitimate ?author=N filter in wp-admin Posts/Pages lists ("All / Mine / <author>" links). Public enumeration block unchanged. Three-line fix.

= 2.1.13 =
Bug fix. Silent 2FA failure on installs with permalink_structure without trailing slash (e.g. /%postname%) — the verify cookie path mismatched the request path after handle_loaded's normalisation. Fixed cookie path to omit trailing slash. Neutral on trailing-slash installs.

= 2.1.12 =
Bug fix. Hide Login rendered without CSS when both apex and www routed to the same WP (shared hosting). Two fixes: canonical-host 301 in Hide Login + host-aware CSP in Login Page Security Headers. Neutral on single-host installs. New filter login_armor_canonical_host_redirect for opt-out.

= 2.1.11 =
Bug fix for multisite + domain mapping: the Hide Login URL is now host-aware (picks home_url or site_url from HTTP_HOST), fixing a 2.1.9 regression where mapped subsites redirected to /wp-admin/ (404). Standard and headless installs keep working.

= 2.1.10 =
Cosmetic fix. The 404 page served when an anonymous visitor hits `/wp-admin/` with Hide Login enabled now renders as a proper WordPress 404 (body class `error404`, SEO `noindex` meta, theme 404 template) instead of a half-bootstrapped page. No security or functional change.

= 2.1.9 =
Bug fix. Hide Login now builds the rewritten login URL from `site_url()` (matching `wp_login_url()` in WP core) instead of `home_url()`. Fixes silent breakage on multisite headless, WordPress in subdirectory, and reverse-proxy installs. Neutral on standard installs.

= 2.1.8 =
Hygiene release after a full 2.1.7 audit. Three LOW fixes: the webhook stats query no longer warns on fresh installs, the lockout_window option is cleaned on uninstall, and five missing French translations were added. No end-user-visible change.

= 2.1.7 =
Preventive: hardens the Email 2FA enrollment flow. Failed `wp_mail()` no longer leaves a half-committed 2FA state, and a new pre-activation modal forces a real test email + a safety-net check before the user can lock themselves out. Recommended for every install where Email-based 2FA is enabled.

= 2.1.6 =
Preventive release. Eliminates a latent V2.1.3-style fatal risk in the TwoFactor module. Finishes the uninstall.php cleanup (zero residual data). Surfaces Activity Log integrity coverage scope in admin UI. No new features, no DB migration.

= 2.1.4 =
Critical hotfix: 2.1.3 fatal-errored on every fresh install (Class "LoginArmor\ActivityLog\ActivityLog" not found). Sites with Activity Log already enabled were unaffected. Recommended for every install, urgent for new installs.

= 2.1.3 =
Critical hotfix: Hardening "Hide WP version" was stripping cache-buster from our own assets, so updates past 2.1.0 were invisible behind hosting CDNs (LiteSpeed LSADC, Cloudflare). Recommended for every install.

= 2.1.2 =
Critical hotfix: the Settings tab fatal-errored on every fresh install that had not yet enabled the Activity Log module (Class WebhookDispatcher not found). Recommended for every install.

= 2.1.1 =
Activity Log integrity: every row is HMAC-signed and chained, detects any tampering. Optional signed webhook forwarding (SIEM / Slack / Datadog / any HTTPS). New WP-CLI verify-chain. Bundles 6 hardening fixes. Migration automatic. Recommended for every install.

= 2.1.0 =
Security: 2FA pending token moved from URL query string to a signed HttpOnly + SameSite=Strict cookie. Closes URL-leak (browser history / Referer / access logs) and DB-leak (clear token no longer in wp_options). Recommended for every install with 2FA enabled.

= 2.0.5 =
Security audit pass: REST author-enum scope, optional HSTS, IPv6 subnet fix, 0.0.0.0 placeholder DoS skip, .htaccess admin-rules preservation. No regression. Recommended.

= 2.0.4 =
Real fix for the lockout 429 page on hosts with a public page cache (LiteSpeed Cache, WP Rocket, Cloudflare). Recommended after the 2.0.1-2.0.3 sequence.

= 2.0.3 =
Hotfix: HTTP/2 stream termination on LiteSpeed/LSAPI for the branded lockout page. Recommended.

= 2.0.2 =
Critical fix: 429 branded lockout page now reaches the browser. Recommended.

= 2.0.1 =
Branded 429 lockout page on the triggering attempt + Reset Stats UI + correct WP.org banner/icon. Recommended.

= 2.0.0 =
First WordPress.org release of the V2 line. Eight independent security modules. Recommended.
