=== Bastora Security Audit ===
Contributors: mathiasva
Tags: security, audit, brute force, hardening, login
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 0.2.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: bastora-security-audit

Honest 52-point security audit for WordPress. Scans internally, hardens key areas, steps aside when another security plugin is active.

== Description ==

**Bastora** is an honest WordPress security audit. Instead of thousands of switches without explanation, the plugin checks your installation against a fixed catalog of **52 security points** and reports the result as a plain-text traffic-light list inside your dashboard.

Bastora is different from other security plugins in three ways:

1. **Honest external view.** Bastora inspects your site the way a bot would: version leaks in the HTML, open listings, missing security headers, exposed endpoints. Most other plugins only check their own configuration.
2. **Conflict-aware auto-hardening.** Hardenings are active by default. Bastora checks whether another security plugin (Wordfence, Solid Security, AIOS, Limit Login Attempts, etc.) already handles the same task, and steps aside elegantly instead of creating a conflict.
3. **Zero configuration.** Install, activate, click "Run scan" once, done. Bastora configures itself.

= What Bastora checks =

* **Access (11 points):** HTTPS login, brute-force protection, salt keys, shared accounts, login behavior
* **System (10 points):** file editor, directory listings, wp-config lockdown, debug mode, file permissions, revisions
* **Information leakage (10 points):** generator tag, RSD link, WLW manifest, XML-RPC, REST API users, pingbacks, X-Powered-By
* **Security headers (5 points):** X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, HSTS
* **Pingbacks (2 points):** outbound and inbound pingbacks
* **Auto-updates (7 points):** nightly protection, minor/major auto-updates, plugin/theme auto-updates, abandoned extensions
* **Monitoring (7 points):** transients, revision cleanup, captcha, WordPress version, PHP version, /uploads/ PHP lockdown, security plugin status

= What Bastora hardens (when no conflict is detected) =

* WordPress version removed from HTML and RSS feed
* RSD link and WLW manifest removed
* Login shake effect disabled
* Login error message generalized (no longer reveals existing usernames)
* Author pages redirected (prevents username enumeration)
* XML-RPC disabled (unless a competing plugin already handles it)
* Pingback XML-RPC methods blocked
* REST API /users endpoint blocked for non-logged-in requests
* Application Passwords disabled
* **Login Honeypot**: hidden form field in the login mask that bots fill out and thereby reveal themselves as bots
* **Brute-force protection with IP lockout**: 5 failed attempts → 30 min lock. On repeated lockouts: escalation to 4 hours, then 24 hours. Counter resets after a successful login. IPv6 is locked on the /64 prefix. Cloudflare and reverse-proxy IP detection is built in.

= Conflict-aware =

If you are already running one of the following plugins, Bastora detects it and disables only the overlapping area:

* Wordfence Security
* Sucuri Security
* Solid Security (formerly iThemes)
* All-In-One WP Security & Firewall
* MalCare Security
* WP Cerber Security
* Limit Login Attempts Reloaded
* Disable XML-RPC
* Disable Application Passwords
* Really Simple SSL
* HTTP Headers

In the dashboard you see the status of each hardening with a plain-language explanation of why it is active or inactive.

= What Bastora deliberately does **not** do =

* **No TOTP enforcement.** SMB owners routinely lock themselves out with TOTP apps. Bastora relies on brute-force protection, rate limiting, and anomaly detection instead.
* **No login URL hiding.** Renaming the login URL breaks the password reset email link as soon as the plugin is deactivated. Rate-limit plus honeypot is the cleaner solution.
* **No cloud connection without consent.** All external connections (including version checks against wordpress.org) are disabled by default. They activate only after you explicitly opt in via the welcome wizard or the settings page.

= Optional anonymous statistics (planned, not yet active) =

A future plugin version will offer optional anonymized security telemetry to bastora.de. **In this plugin version, no telemetry is sent. The opt-in toggle only stores your consent for a future release.** Once the sender pipeline goes live in a later release, only the following anonymized technical values would be transmitted:

* WordPress, PHP and MySQL version strings
* Locale (for example de_DE)
* List of installed plugin slugs (without versions)
* Audit results (which of the 52 points are red, yellow, green)
* A random anonymous site ID (UUID) generated locally on first plugin start

What would **never** be transmitted: domain, URL, IP addresses, email addresses, usernames, post content, file content.

== Installation ==

1. Install the plugin from the WordPress plugin directory or upload the ZIP folder to `/wp-content/plugins/`.
2. Activate the plugin in the "Plugins" menu.
3. Open the new "Bastora" menu and click "Run scan" once.

That is all. Bastora configures itself.

== Frequently Asked Questions ==

= Do I need technical knowledge to use Bastora? =

No. Bastora needs no configuration. Install, activate, scan — done.

= Does Bastora work alongside Wordfence/Sucuri/Solid Security? =

Yes. Bastora detects these plugins on activation and steps aside in overlapping areas. The dashboard shows which hardenings are inactive due to conflicts.

= Does the plugin transmit data from my site? =

By default nothing. The only external connections this version makes are opt-in version checks against api.wordpress.org (slug-only, no domain, no user data). The anonymous-statistics telemetry pipeline to bastora.de is **not active in this version** — the opt-in toggle in the settings page only stores your consent for a future release.

= How do I revoke the statistics opt-in? =

Bastora → Settings → uncheck "Zustimmung vormerken" → Save. Since no data is sent in this plugin version, revoking simply clears the stored consent.

= Where is the data stored? =

On German servers. Bastora works exclusively with a German hoster.

= What happens when I uninstall Bastora? =

On normal deactivation, Bastora settings are preserved. If you remove the plugin via "Delete", all settings, audit reports and site IDs are removed. Hardenings are automatically rolled back.

= When does the printable report arrive? =

In one of the next plugin versions. As of 0.1.0 the report is available as HTML inside the dashboard.

== Changelog ==

= 0.2.2 =
* Plugin Review Team feedback: all paid-tier markers removed. The dead `premium_only_ids()` list, the dashboard upsell block, the report's premium section and the wizard's paid-service step are gone. The wizard now has three steps (opt-in → scan → activation). No more references to a paid tier inside the plugin code, the admin UI or the printable report.
* Conflict-check marker constant renamed from `BASTORA_PRO_SECURITY_LAYER_VERSION` to `BASTORA_MANAGED_LAYER_VERSION` (neutral naming, no Pro/Premium connotation).
* readme.txt: paid-service section removed.
* Telemetry consistency: the opt-in toggle in the welcome wizard and in settings now clearly states that the bastora.de sender pipeline is **not active in this plugin version**, the toggle only records consent for a future release. readme.txt Privacy section aligned to match.
* Scanner: `check_monitor_03` (captcha plugins detection) and `check_monitor_07` (security plugin detection) now read `active_plugins` directly from the option instead of loading `wp-admin/includes/plugin.php`. One less `require_once` of a core file.

= 0.2.1 =
* Plugin-Name auf „Bastora Security Audit" gekürzt (deckungsgleich mit dem Slug, kein Sonderzeichen im Header).
* `Donate link` aus `readme.txt` entfernt (verwies auf die Produktseite, keine echte Spenden-URL).
* `== Screenshots ==`-Sektion temporär aus `readme.txt` entfernt. Wird wieder aufgenommen, sobald die Bilder im WordPress-Assets-Verzeichnis liegen.
* MU-Plugin-Konflikt-Check liest jetzt zusätzlich eine Marker-Konstante. Quellcode-Kommentar produktneutral formuliert.

= 0.2.0 =
* Neuer Onboarding-Wizard mit schrittweiser Aktivierung der Härtungen plus Vorher-Nachher-Vergleich.
* Härtungen werden erst nach dem ersten Klick auf „Jetzt absichern" im Wizard scharf geschaltet. Davor läuft das Plugin im reinen Mess-Modus.
* Bisheriges Welcome-Banner mit Zwei-Häkchen-Block durch den Wizard ersetzt.

= 0.1.6 =
* Plugin Review Team-Feedback: `Author URI` aus dem Plugin-Header entfernt, da identisch mit `Plugin URI`. Nur noch eine URI im Header.

= 0.1.5 =
* Welcome-Banner und Bericht: Inline-`onclick`-Handler durch enqueued JavaScript ersetzt (`assets/admin.js`, `assets/js/report.js`).
* Inline-`style`-Attribute im Welcome-Banner und im Login-Honeypot in Utility-Klassen (`assets/admin.css`, `assets/css/login-honeypot.css`) ausgelagert.
* Menü-Icon nutzt jetzt das WordPress-Standard-Dashicon `dashicons-shield` statt eines `base64`-Inline-SVG.
* `$_POST`-Werte im Welcome- und Settings-Handler durchlaufen jetzt zusätzlich `wp_unslash` + `sanitize_text_field`, auch wenn sie nur als Bool genutzt werden.
* Plugin-Header um `Author URI` und `Domain Path` ergänzt.

= 0.1.4 =
* Konflikt-Check liest die aktiven Plugins direkt aus der `active_plugins`-Option und lädt `wp-admin/includes/plugin.php` nicht mehr unnötig. Vermeidet einen `require_once` ohne unmittelbar folgenden Funktions-Aufruf.

= 0.1.3 =
* Konflikt-Check erkennt jetzt auch MU-Plugin-basierte Sicherheits-Schichten (Marker-Konstanten/Funktionen). Plugin zieht sich automatisch in den überlappenden Bereichen zurück (XML-RPC, REST users, Security Headers, Brute-Force, Honeypot, Application Passwords), damit Filter nicht doppelt feuern und der Bastora-Honeypot auf Whitelabel-Sites unsichtbar bleibt.

= 0.1.2 =
* External version-check calls to api.wordpress.org are now opt-in by default. Welcome banner uses two separate checkboxes (external calls + anonymous statistics), each independently toggleable in the settings page.
* Update-related audit points (update.06, update.07, monitor.04) report "not checkable" when the user has not enabled external calls.
* Privacy section in readme.txt expanded with the exact endpoint URLs and opt-in mechanics.

= 0.1.1 =
* Text domain aligned with plugin slug (bastora-security-audit)
* Printable report CSS moved from inline style to enqueued stylesheet
* Contributors list corrected to plugin author account

= 0.1.0 =
* Initial release
* Scanner covering all 52 audit points
* 11 conflict-aware filter hardenings
* Conflict detection for 13 known security plugins
* Admin dashboard with status card, findings list and hardening overview

== Upgrade Notice ==

= 0.2.2 =
Plugin Review Team feedback: all paid-tier markers removed from code, UI and report. Wizard is now three steps. Marker constant for the conflict-check renamed to a neutral name.

= 0.2.1 =
Vorbereitung für die Einreichung im WordPress-Plugin-Verzeichnis: Plugin-Name, Donate-Link und Screenshots-Sektion bereinigt.

= 0.2.0 =
Neuer Onboarding-Wizard mit vier Schritten plus echtem Vorher-Nachher-Vergleich. Härtungen werden erst nach Klick scharf geschaltet, das Plugin misst vorher nur.

= 0.1.6 =
Plugin Review Team-Feedback: doppelte URI im Header entfernt.

= 0.1.5 =
Plugin Review Team-Vorbereitung: Inline-`onclick`/`style`/`base64`-SVG durchgängig in enqueued Assets bzw. Dashicons ausgelagert; POST-Sanitization gehärtet.

= 0.1.4 =
Plugin Review Team feedback: unnötiges `require_once` von `wp-admin/includes/plugin.php` im Konflikt-Check entfernt.

= 0.1.3 =
Konflikt-Check erkennt jetzt auch MU-Plugin-basierte Sicherheits-Schichten — verhindert Filter-Doppelung und Whitelabel-Brüche.

= 0.1.2 =
External calls to api.wordpress.org are now opt-in by default — review your settings after upgrade if you rely on the update-related audit points.

= 0.1.1 =
Plugin Review Team feedback: text domain alignment, CSS enqueue, contributors fix.

= 0.1.0 =
Initial release.

== Privacy ==

= External service connections =

Bastora contacts external servers in two clearly separated cases. **Both are opt-in. By default the plugin makes no external connections.**

**1. Version checks against api.wordpress.org (opt-in)**

When the user enables "Versions-Abgleich erlauben" in the welcome wizard or settings page, Bastora queries api.wordpress.org during a manual scan for:

* The current WordPress core version: `https://api.wordpress.org/core/version-check/1.7/`
* For each detectable plugin, its last update date: `https://api.wordpress.org/plugins/info/1.0/<slug>.json`
* For each detectable theme, its last update date: `https://api.wordpress.org/themes/info/1.2/?action=theme_information&request[slug]=<slug>`

This is the same API WordPress itself uses for its own update checks. Only the slug of each plugin or theme is transmitted. No domain, no user data, no visitor IP data. Calls run only on manual scan-button clicks, never automatically in the background. Responses are cached for 24 hours.

If the user does not opt in, the update-related audit points are marked "not checkable" and no request is made.

**2. Anonymous telemetry to bastora.de (planned, not active in this version)**

A future plugin version is planned to offer optional anonymized telemetry to bastora.de. **In the current plugin version this pipeline is not implemented — no `wp_remote_post`, no payload, no transmission to bastora.de occurs anywhere in the codebase.** The opt-in toggle in the settings page only stores the user's consent for a future release.

When the sender pipeline goes live in a later release, the following anonymized values would be transmitted:

* WordPress, PHP and MySQL version strings
* Locale code (for example de_DE)
* List of installed plugin slugs (without versions)
* Theme slug of the active theme
* Audit results: per security point the status (passed / warning / failed)
* A random anonymous site ID (UUID) generated locally on first plugin start

What would **never** be transmitted: domain, URL, IP addresses, email addresses, usernames, post content, file content, database content.

= Privacy notice =

Full privacy notice: https://bastora.de/datenschutz.php
Responsible party as per imprint: https://bastora.de/impressum.php
