=== BetterShield ===
Contributors: wpdevteam
Tags: security, audit, hardening, activity log, recovery
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.0.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Find out what is actually wrong with your site’s security, in plain language, then fix what you want. Every change can be undone.

== Description ==

Most security plugins tell you that you are protected. This one tells you what it found.

BetterShield reads your site — an audit never writes anything — and reports what it saw: a score you can see the workings of, and every finding written out in plain language with what it is, why it matters, and what could break if you act on it. Then you decide. Nothing on your site changes until you press a button, and every button has an undo that puts back exactly what was there before.

The whole diagnosis is free, and the whole diagnosis is shown. Nothing is summarized, held back or counted for you and revealed later. There is no account to make and nothing about your site is sent anywhere.

It is also built to stay out of the way. The only thing running for your visitors is whichever fixes you turned on, activity is written after the page has been sent rather than during it, and on the WooCommerce cart and checkout nothing is added at all.

= What it checks =

Forty read-only checks across access, exposure, updates and extensions, server settings and configuration: an account named “admin”, user profiles anyone can list, XML-RPC, the dashboard file editor, the WordPress version in every page, missing security response headers, a site address that is not HTTPS, a PHP version that no longer receives security fixes, the keys in wp-config.php, the default database table prefix, scheduled events nothing answers, a plugin the WordPress.org directory has closed, an account that can change the site and nobody has used for months, files that no longer match the official copies, and more.

Anything that could not be checked says so rather than reading as a pass, and a site whose first audit has not run has no score at all — nothing found and nothing looked for are not the same thing.

= What you can fix in one click =

There are fifteen one-click fixes: XML-RPC, the dashboard file editor, public user listing, security response headers, PHP running in the uploads directory, uploads directories listing their contents, sensitive files a stranger can download, the sign-in address, application passwords, the dashboard for signed-out visitors, low-privilege accounts in the dashboard, publishing the WordPress version, the keys that sign every sign-in, telling browsers to refuse plain HTTP, and finding out what a content policy would break before anything breaks.

Each one shows what it will change before it changes anything, warns you when another plugin is already doing the same job, and can be undone at any time — the undo never expires. A fix that writes to a file records what was there first and restores it byte for byte, and a fix that cannot work on your server says so instead of reporting success.

= Signing in =

Two-factor with any authenticator app and ten single-use backup codes. Passkeys — your fingerprint, your face or your device PIN — with the private half of the key never leaving your device. Lockouts after repeated wrong passwords from one connection, an allowlist of addresses that must never be locked out, and a blocklist that refuses sign-in while leaving ordinary browsing alone. An optional idle timeout, an optional cap on sessions per account, and a view of who is signed in from where.

None of it can lock you out while you set it up. Nothing is enforced until you have proved your authenticator generates working codes and confirmed you stored the backup codes, and a second factor required for a role is asked for inside the dashboard rather than at the sign-in, so it can never be the reason somebody cannot get back in.

= If you are ever locked out =

Activating the plugin emails a single-use recovery link to the site’s administration email. Opening it pauses every protection for an hour and leaves your settings exactly as they are, which is enough time to get back in and sort things out. Using a link issues the next one straight away — on the page and by email — so using one never leaves you without one. You can also print a set of offline codes and keep them somewhere that is not this site.

= The activity log =

Sign-ins and sign-outs, account and role changes, email address changes and password resets, application passwords, plugin, theme and core changes, and everything the plugin does itself — each with who, what and when. Filter it by area, by person and by date, search it, and export what you are looking at as a CSV file. Rows are removed after thirty days.

Each day is sealed and chained to the day before, so an edit or a deletion inside that window shows. It is not tamper-proof and does not claim to be.

= Alerts =

A weekly summary by email that arrives on quiet weeks too, saying so — a summary that only turns up when something is wrong teaches its reader to dread it. Between summaries, an event rated high or critical is emailed on its own. Every message says what happened, why it matters and one thing to do, in that order, then links to the exact finding rather than to a dashboard. One switch mutes all of it, and while it is on both the Overview and the dashboard widget say so: a silenced site and a quiet one should never look the same.

No message this plugin sends contains an upgrade prompt, a price, or a link to buy anything, and a test in the plugin’s own suite fails if one ever does.

= Your files against the official copies =

Not a signature scanner, and no claim to recognize malicious code. Your WordPress core files and the plugins you installed from the directory are compared against the copies WordPress.org publishes, and anything that differs is shown with the actual difference, line by line. One click fetches the official copy, checks it against the published checksum before writing anything, and puts the file back — keeping the one that was there rather than deleting it. A file you changed on purpose can be marked expected, and a plugin whose copy differs from the published one can be adopted at that version.

Anything with no official copy — a commercial plugin, your own code — is named as unverifiable rather than counted as clean. Silence is never allowed to read as approval.

= Also =

`wp bettershield audit`, `findings`, `harden`, `activity`, `recover`, `integrity` and `settings` on the command line, so a hundred sites need not be a hundred clicks, and every change made there lands in the activity log. Settings export and import as one file. Findings in Site Health. A dashboard widget. A report of what agents and connected tools can do on this site — and, on WordPress 6.9 or newer and only if you switch it on, an AI agent you connect to your site can read its security state through eighteen bounded, read-only abilities. The account’s permissions still apply, and these abilities cannot change the site.

Multisite networks are supported. The network administrator gets every site’s score in one table, can set the two-factor and passkey rules once for every site, and has a recovery link of the network’s own.

There is no firewall. Audits only read, every change can be undone, and the only outside services contacted are WordPress.org’s own — and, if you connect one to WordPress, your own AI provider.

== Installation ==

1. Install it from the plugins screen, or upload the folder to `/wp-content/plugins/bettershield`.
2. Activate it. A read-only audit runs immediately, and your recovery link is emailed to the site’s administration email.
3. Open **BetterShield** in the admin menu.

Nothing on your site is changed until you choose a fix and apply it.

== Screenshots ==

1. The Overview after the first audit: the score, the three fixes worth doing first, and what changed since your last visit.
2. Every finding with its severity, why it matters, and a fix or a reason to mark it not applicable.
3. One-click hardening. Each item previews what will change and has an undo that never expires.
4. Login protection: how the site sees a connection, attempt limits, lockouts, and the addresses always allowed or never allowed.
5. The activity log: who did what and when, with filters, search and a CSV export.
6. Files compared against the copies WordPress.org publishes, with the difference shown and one click to put a file back.

== Frequently Asked Questions ==

= Is it free? =

Yes. Every finding, every explanation and every point of the score is free, and so is every fix, two-factor, passkeys, login protection, the recovery link, the activity log and the file comparison. No account, no payment, and nothing withheld to make a point.

There is a separate add-on, BetterShield Ultra, for people who look after sites for others: trusted devices, sign-in screens carrying your own branding, Slack and webhook alert channels, a scheduled report to send a client, temporary access that ends on its own, an hourly check of the code nobody publishes, and a longer activity history. It is a paid purchase and it is nobody’s idea of a requirement — nothing in this plugin is reduced or held back without it.

= Will it slow down my site? =

Rather than answer that, the Overview measures it and shows you the number for your own site: how many database queries and how many milliseconds this plugin added to the pages your visitors actually loaded. It is measured on a sample of real page views, and the panel says what was counted and how large the sample was.

The design behind the number: the only thing running for your visitors is whichever fixes you turned on, activity is written after the page has been sent rather than during it, and on the WooCommerce cart and checkout nothing is added at all.

= What happens if I lock myself out? =

Open your recovery link. Every protection pauses for an hour and your settings stay exactly as they are, which is enough time to log back in and sort things out. The link is emailed when you activate the plugin, and you can generate a fresh one from Protect → Recovery at any time. Generating a new one stops the old one working.

Each link works once. The page you land on shows you your next link straight away and emails a copy, so using one never leaves you without one — keep it as carefully as a password.

= Does it send my data anywhere? =

No. There is no account, and nothing about your site is sent anywhere. BetterShield contacts WordPress.org’s own addresses — and your own AI provider, if you have connected one to WordPress and you press Explain — and the WordPress.org requests only ask public questions: what are the official checksums for this version of WordPress, and for this version of this plugin. The answers are what let it tell you a file has been altered. Those requests carry the versions of the public software you have installed, which is unavoidable in asking the question, and nothing else: no site address, no email, no username, no keys. They happen on a schedule, when you press a button, and when a plugin is installed or updated, including automatic updates — never while a visitor is loading a page. “External services” below names them.

Every email it sends goes through WordPress to an address on your own site and nowhere else: your recovery link to the admin address; a link that clears a lockout sooner, sent to the address of the account someone was guessing at; the weekly summary; and an event rated high or critical, on its own. The weekly summary and the instant alert go to the addresses you choose under Settings → Alerts, or to the site’s administration email if you choose none, and one switch on that screen stops all of it.

= Will the fixes break my site? =

Each one tells you beforehand what it changes and what could break, and each one can be undone at any time. If you apply something and regret it, the undo restores exactly the state that was there before.

= Does it work on a multisite network? =

Yes. Each site keeps its own findings, settings and fixes, and the network administrator gets a screen of its own: every site’s score and open findings in one table, the whole network’s activity log, a two-factor or passkey rule set once as a floor under every site, and a recovery link for the network itself.

= What happens if I delete the plugin? =

Its records stay by default — the activity log, the findings and the undo history — so reinstalling picks up where you left off. One switch under Settings removes them at deletion instead.

Copies of files it has put back are kept either way, in `wp-content/uploads/bettershield-quarantine/`. When you restore a file, the version that was there is kept rather than deleted, and that copy may be exactly what somebody put on your site — so deleting it on the way out is not a decision this plugin makes for you. Remove them one at a time from the Files tab before you delete the plugin, or delete the folder yourself afterwards.

== External services ==

BetterShield contacts four addresses operated by WordPress.org, which exist for one feature: checking whether the files on your site still match the official ones, and putting an official file back if you ask it to. It contacts your own AI provider only if you have connected one.

**api.wordpress.org** — two public questions. The published checksums for your version of WordPress, contacted when the file check runs on its schedule and when you start one yourself; that request carries the WordPress version and language you have installed, and comparing your files against the official ones is impossible without knowing what the official ones are. And once a day, whether the directory still lists a plugin you installed from it — a few plugins per day, each answer kept for a week, and the request carries that plugin’s directory slug and nothing else. A plugin the directory has closed gets no further updates, and that is worth telling you.

**downloads.wordpress.org** — the published checksums for a plugin installed from the WordPress.org directory, at the exact version you have. Contacted during the same check, and again whenever a plugin is installed or updated, including automatic updates — that is the one moment the copy that arrived can be compared with the published one before it replaces what is already there. The request carries the plugin’s directory slug and its version number.

**core.svn.wordpress.org** and **plugins.svn.wordpress.org** — the official copy of one file, fetched only when you press Restore on a changed file. The request carries the version and the path of that one file. Whatever comes back is checked against the published checksum before anything is written: if it does not match, nothing is written and you are told. That check is what makes fetching a file safe — the copy is verified, not trusted.

**Your own AI provider**, and only if you have connected one to WordPress and only when you press “Explain this in plain language” on a finding. WordPress sends the request using the connector you configured under Settings → Connectors; BetterShield never sees, asks for or stores the key. What travels is the finding’s title, its severity, the plugin’s own description of it, and the evidence the scanner recorded — counts and flags such as “2 accounts” or “scheme: http”. Anything shaped like a web address or an email address is stripped before sending, and file contents, usernames, keys and your site’s address are never included. Connect no provider and the feature is simply not there.

None of the WordPress.org requests carries anything about your site: no site address, no email address, no username, no IP address, no keys, no file contents, and no identifier of any kind. There is no account and no registration. Requests happen on a schedule, when you press a button, and when a plugin is installed or updated, including automatic updates. None of them happens while a visitor is loading a page. If a service cannot be reached, the check says it could not run — it never reports a file as unchanged on the strength of an answer it did not get.

These services are provided by the WordPress Foundation. Terms of use: https://wordpress.org/about/privacy/ and https://wordpress.org/about/privacy/cookies/

**Published vulnerability advisories** — not contacted in this version. The plugin has a daily check that would compare the plugins and themes installed against published advisories, and it says on the Findings screen that no data source is connected, rather than showing an empty list as a clean bill of health. When a source is connected in a later version, this section will name it, link its terms and privacy policy, and state exactly what is sent — the directory slugs and version numbers of what is installed, and nothing else — and the check will stay off until you turn it on under Settings.

== What it keeps about people ==

BetterShield keeps four kinds of thing that belong to a person rather than to the site, all of it on your own server and none of it sent anywhere.

**The activity log** records what happened and who did it: the account, the name it had at the time, and the network the request came from. Addresses are truncated before they are stored — the first three parts of an IPv4 address, the first four groups of an IPv6 one — so what is kept is a network and never the address itself. Rows are removed after thirty days.

**Sign-in attempts** record the username tried, the outcome, and the same truncated network, alongside a keyed digest of the address that reverses to nothing and exists only so two attempts from one place can be recognized as one place. These are working data for the lockout decision and are pruned aggressively.

**Passkeys** record the name you gave the device, when it was added, and when it was last used. The key material is public by definition; nothing secret is stored.

**Account records** are what this plugin has to remember about a person to do its job: whether two-factor is set up and the shared secret and backup codes that make it work, whether the password was below your policy the last time it was seen, when a two-factor deadline started for that account, a confirmation of the password that lasts a few minutes, when this plugin last saw the account sign in, and how far you had read on its own screens. The network each open session is on is kept in WordPress’s own session record, truncated the same way as everything else here.

Under Tools → Export Personal Data, BetterShield answers with all of the above for one account, a page at a time. Under Tools → Erase Personal Data it removes that person’s passkeys, their sign-in attempts and their account records — the second factor and its backup codes among them — and takes their name and network out of the activity rows while keeping the rows themselves. Two things are kept on purpose, and both are reported to you rather than done quietly. The activity rows are the record of what happened to your site, including anything done while an account was in somebody else’s hands, and a security log that can be emptied on request is one an intruder can empty. The date of the last sign-in is what tells you which accounts with real permissions nobody is using any more, and an account that reads as never used is one nobody is ever asked to close. The full list — every record this plugin keeps about a person, with the reason it is kept and how long it is kept for — is under Tools → Site Health → Info, and the export carries it alongside the records themselves.

== Source code ==

Everything that runs is readable in the plugin folder.

The PHP in `src/` is the code that runs. Nothing about it is generated, compiled, or minified.

The admin interface is compiled, and everything it compiles to is in `assets/build/`: the scripts and stylesheets the admin screens load, their right-to-left stylesheets, and the small generated PHP files that list what each script depends on. All of it is built from the files in `assets/js/` and `assets/css/`, which ship in this plugin next to them.

To rebuild them from the sources included here:

`npm install`

`npm run build`

The build uses @wordpress/scripts, which is declared in the `package.json` included with the plugin.

== Changelog ==

= 1.0.0 =
First public release.

* A security audit of forty read-only checks, with a score you can see the workings of and a plain-language explanation of every finding.
* Fifteen one-click fixes, each showing what it will change first, and each with an undo that never expires.
* Two-factor sign-in with any authenticator app, ten single-use backup codes, and passkeys.
* Login protection: lockouts after repeated wrong passwords, an allowlist and a blocklist, session limits and an optional idle timeout.
* A recovery link, safe mode and printed offline codes, with daily readiness checks and optional weekly email tests. No recovery credential is spent by a check.
* An activity log of sign-ins, accounts, roles, plugins, themes and this plugin’s own doings, with filters, search, a CSV export and a daily seal.
* Core and directory-plugin files compared against the copies WordPress.org publishes, with the difference shown and one click to put a file back.
* A weekly email summary that arrives on quiet weeks too, and high and critical events sent on their own.
* WP-CLI commands, settings export and import, findings in Site Health, a dashboard widget, and a report of what connected agents can do here.
* Multisite networks, with every site’s score in one table and rules a network can set once.
