=== Nolimit Security ===
Contributors: kristianwind
Tags: security, firewall, malware, two-factor, login
Requires at least: 5.8
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.2.2
WC requires at least: 6.0
WC tested up to: 11.1.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Firewall, login protection, country filtering, honeytraps, malware and vulnerability scanning, and an AI analyst — with no telemetry and no cloud account.

== Description ==

A complete security plugin for WordPress and WooCommerce that does not phone
home, does not require an account anywhere, and does not send your visitors'
addresses to a third party in order to protect you from them.

= The firewall =

Inspects every request before WordPress decides what to do with it, against
about sixty rules covering SQL injection, cross-site scripting, path traversal,
remote and local file inclusion, code execution, malicious uploads, the
WordPress-specific attacks, known scanning tools and malformed requests.

Each rule scores according to how little else a match could be, and a request
is refused when the total reaches the threshold for the sensitivity you chose —
so a single unmistakable attack is enough on its own, while two weak signals
have to agree.

* **Watching mode** records what it would have refused and refuses nothing. It
  is the honest way to switch a firewall on in front of a site that is already
  taking money.
* **Extended protection** writes one small file into `mu-plugins` so the
  firewall runs before any other plugin loads — before the code a request might
  be attacking. It removes itself when this plugin is deactivated.
* **Content rules are not applied to people who can edit posts.** The body of a
  request from an editor is a blog post, and a blog post about SQL injection
  contains SQL injection. That exemption is the single largest source of false
  positives in WordPress firewalls, and everything else still applies to those
  users.

= Login protection =

Attempt limiting where a lockout stops somebody logging in and nothing else —
the site stays readable, because a customer who has forgotten their password is
not an attacker. Only after three lockouts in a day does it become a real block.

Also: one error message whether the username or the password was wrong, an
invisible form field with a signed timestamp, username-probing blocked in all
three places WordPress leaks it, XML-RPC restricted or switched off, leaked
passwords refused via a check that never sends the password, and TOTP
two-factor authentication with recovery codes.

= Country filtering =

Block or allow by country, per area of the site — the whole site, the login
form, XML-RPC, the REST API, comments, registration, the WooCommerce checkout.
Verified search engines are never refused, and a visitor whose country is not
known is never refused either.

The country database is downloaded and compiled locally. No lookup leaves the
site.

= Traps =

A path that is forbidden in robots.txt and linked nowhere visible; an optional
decoy login form; invisible fields on the login, registration and comment
forms; and the thirty-odd paths that exist in no WordPress installation and are
asked for every day. A trap has no false positives to tune.

= The scanner =

* WordPress core files verified against wordpress.org's published checksums.
* Every file compared against what it looked like at the last scan, with the
  plugin and theme version taken into account — so an update is not reported as
  four hundred modified files.
* Malware signatures written to match the combination rather than the
  ingredient, so `base64_decode` on its own is not a finding.
* Published vulnerabilities for core, every plugin and every theme.
* A configuration audit, and an audit of the accounts that can do damage.

= The AI analyst =

Optional, off by default, and it works with whichever provider you have:
OpenAI, Anthropic, DeepSeek, OpenRouter, Groq, Mistral, Together, a model
running on your own server through Ollama or LM Studio, or anything else that
speaks the OpenAI API.

Five levels, from "answers when asked" through a daily briefing and proactive
triage to acting within a list of actions you wrote. Everything it does is
logged, reversible, and refused outright if it is not on that list.

What may be sent is six separate switches, and a button on the settings screen
renders the actual payload — not a description of it.

= Getting back in =

A security plugin is the one kind of plugin that can lock its owner out of the
site it protects. There is a line for wp-config.php that switches every
blocking decision off without needing the database, and a set of WP-CLI
commands that undo any of it from a shell.

== Privacy ==

**This plugin contains no telemetry.** It does not report anything about this
site to its author, and there is no account to create.

It makes exactly four kinds of outbound request, all of them to third parties
rather than to us, and every one can be switched off:

1. **The update feed** — a plain unauthenticated GET for the plugin's own
   release, with the WordPress user agent replaced so the site's address is not
   in it.
2. **Threat lists and the country database** — downloaded whole and compiled
   locally, specifically so that no visitor's address is ever sent anywhere. A
   reputation API would mean doing exactly that, on every request.
3. **Vulnerability lookups** — one plugin or theme slug per lookup, with no site
   address, no identifier and no version number. This is the site's inventory
   leaving the site, one name at a time, and it can be switched off on the
   Scanner screen.
4. **The AI analyst, when you switch it on** — to the provider you configured,
   with the key you supplied, containing what the six sharing switches allow.

The leaked-password check sends the first five characters of a SHA-1 hash of
the password and nothing else; the service answers with several hundred leaked
hashes beginning with those characters and the comparison happens here.

Passwords are never written to the log, including the ones submitted to the
decoy login form.

== Frequently Asked Questions ==

= I have locked myself out. =

Add this to wp-config.php, which you can reach over FTP, SSH or a hosting file
manager:

`define( 'NLSEC_DISABLE', true );`

Every blocking decision stops immediately and the admin screens keep working,
so you can find the setting that caused it. Nothing in the database can
override that line.

With shell access and WP-CLI: `wp nlsec panic`, or
`wp nlsec unblock 203.0.113.9 --allow`.

= Somebody has lost the phone with their second factor. =

`wp nlsec 2fa reset <user>` from a shell, or clear it from their profile as an
administrator. That lets them set a new one up — nobody can set one up on
somebody else's behalf, here or anywhere, because a second factor another
person enrolled is not a second factor.

= Does it work with WooCommerce? =

Yes, and it knows about it: the account login and registration forms, the
checkout as a filtering scope, and shop managers counted as accounts worth
protecting harder. It does not require WooCommerce.

= Will it slow the site down? =

The firewall reads one autoloaded option and, when the block list is empty,
touches no table at all. Rate limiting costs two small writes per request and
says so next to its switch. The country and threat-list lookups are binary
searches in a file, with no memory cost. The scanner runs from the scheduler,
in steps, against a time budget.

= The scanner found nothing. Is the site clean? =

It means nothing was found, which is not the same thing. Signature matching
finds what is known, and whatever got in yesterday is by definition not in
yesterday's list. The core checksums and the file-change baseline are the parts
that catch what signatures cannot.

== Changelog ==

= 1.0.0 =
First release.
