SecureLite Security — changelog, 0.1.0 to 0.2.21

Newer versions are listed in readme.txt and on the plugin page at WordPress.org.

= 0.2.21 =
* The "PHP execution blocked in uploads" check now gives a clear answer on many more sites. If your uploads folder already holds a harmless PHP file (many plugins leave an empty "index.php" there), the check asks your server for that real file: refused means PHP is blocked, run means it is not. SecureLite reads the file first and only uses one that contains no code, and it never creates, changes or removes anything in your uploads folder.
* Fixed: on sites whose WordPress address starts with http:// while the host forces https://, this check stopped at the redirect and reported "Inconclusive: the server answered with HTTP 301". It now follows a redirect that only changes http/https or "www.", and nothing else.
* When the check still cannot decide (for example on LiteSpeed hosts with no harmless PHP file in uploads), it explains why and how to check by hand, instead of showing a bare status code.
* The plugin description now says what the simulation does today: it proves each protection works on your own site. The old wording, "attacks your own site", dated from before 0.2.17, when the checks were still sent over the network.

= 0.2.20 =
* Other plugins' notices, promotions and review requests no longer appear inside SecureLite's screens. They used to land in the Agent status card on the dashboard and stretch the page. SecureLite now leaves them out on its own screens only; WordPress update and recovery notices, and SecureLite's own messages, still show. Every other admin screen is unchanged, so those plugins' notices still appear wherever else they normally do.
* Any notice that does reach a SecureLite screen now sits above the cards instead of inside them.

= 0.2.19 =
* Attack Simulation now proves that real requests reach the protections it tests. A new first check sends one normal page request to your site (no attack, no login) and passes only if SecureLite's firewall itself inspected it. If a page cache, your host or another plugin answers instead, the report says so rather than counting it as a pass. Together with the thirteen attack checks, "Every attack was blocked" now means the attacks would be refused on your site, not only by SecureLite's rules in isolation.
* If a CDN or proxy sits in front of your site (Cloudflare, Sucuri, CloudFront, Fastly, QUIC.cloud, LiteSpeed, Varnish), the report names it from the evidence it already has. It is detected, not tested.
* Every report, live and printed, now ends with a plain line saying what was tested and that your host's or CDN's own firewall is not part of the test.
* Fixed: a re-test of the firewall or login checks was meant to make no request to your server since 0.2.17, but still asked for your home page first. It now only does so when a check needs the server's answer.
* The Support screen's local-site lockout hint reads more clearly.

= 0.2.18 =
* The plugin's name now matches its WordPress.org listing: SecureLite Security – Firewall, Malware Scanner & Attack Simulation. Nothing else about the plugin changes.
* The plugin description on the Plugins screen no longer says it makes no outbound connections. The malware scan does ask WordPress.org for official file checksums, as the readme has always disclosed under External Services; the description now says what is true: nothing about your site is sent anywhere.
* A one-minute video on the plugin page shows install to first Attack Simulation.

= 0.2.17 =
* Attack Simulation is now safe to run on a live site with nothing to set up. No attack and no login is sent over the network any more: each attack runs against SecureLite's real firewall, upload, enumeration, XML-RPC and lockout code inside WordPress, as data held in memory. Your host's firewall (Imunify360, ModSecurity, LiteSpeed), your CDN and other security plugins never see a test, so they have no reason to briefly ban the server's own address, and nobody receives "brute-force attack detected" emails.
* The brute-force check no longer sends failed logins. It first confirms that SecureLite's lockout is attached at every point of the login, then trips the real lockout from a reserved test address, and deletes its own counters before the step ends. If a step dies halfway (a host time limit), what it created is removed the next time the simulation runs or the Verification screen opens.
* Test events no longer appear in the security log, on the dashboard or in the daily summary.
* The .git and readme.html checks read your disk first. If there is no .git folder, or readme.html is missing or does not reveal your version, the check passes without asking the server anything.
* If the site cannot reach itself over HTTP, the simulation still runs: only the checks that need the server's answer report that they could not be tested.
* New: if XML-RPC blocking or user-enumeration blocking is switched on while login protection is off, the check now says these run as part of login protection, instead of reporting a plain failure. It also reports when another plugin turns XML-RPC back on.
* The simulation only asks your server for its home page when a check actually needs the server's answer, so a re-test of the firewall or login checks makes no request at all.
* Locked out of a site on your own computer? The Support screen, Settings and FAQ now say that on localhost your address is ::1 or 127.0.0.1, not your internet address, so a trusted-IP line with only your public address does not match.
* A run no longer lifts lockouts on the server's own address or 127.0.0.1. Earlier versions did this to undo their own test logins; behind a misconfigured proxy that could have released a real attacker.

= 0.2.16 =
* After an Attack Simulation in which every attack was blocked, one quiet line asks whether you would leave a review on WordPress.org, with "Leave a review" and "Not now". Either answer hides it for good. It never appears after a run with failures, and never on a site where a Support contact (such as the agency that looks after it) is set.

= 0.2.15 =
* Fixed: in WordPress Playground, including the Live Preview on WordPress.org, Attack Simulation reported the brute-force check as failed. Playground signs in every request automatically, so the test's deliberately wrong logins were accepted. The test now opts out of that, and the check works there as it does on a real site.
* Attack Simulation: "Enable & re-test" now re-tests only the checks the change affects (for example the six firewall checks), in a few seconds, instead of running every attack again. The other results stay as they were, and re-tested rows are marked. When more than one protection can be turned on, an "Enable all & re-test" button does them together. "Run again" is still the full test.
* When Attack Simulation's live view cannot start because something answers in its place (a firewall or another security plugin blocking admin-ajax.php, a hosting time limit, a PHP error), it now says so, with the HTTP status and page title, instead of "Unexpected token '<'". A button runs the simulation without the live view, which does not need admin-ajax.php.
* The firewall checks now follow a redirect that keeps the test attack in the address (for example http to https, or another plugin's redirect) and judge where it lands, as a real attacker's request would. Previously such a redirect was reported as "Not blocked (HTTP 301)". A redirect that drops the attack is reported as "could not test", with where it went.
* The firewall checks in Attack Simulation now use a fresh test address on every run, so a page cache or CDN can no longer answer with a response stored on an earlier run (results that flipped between Passed and Failed).
* The uploads check no longer reports "your server ignores the rule" when it cannot actually tell. On LiteSpeed servers (Hostinger and many other hosts) a request for a missing file is answered by WordPress before the uploads rule is applied, so the check now says it could not confirm and explains a 30-second manual test.

= 0.2.14 =
* Two-factor setup shows a QR code: point your authenticator app at the screen instead of typing a 32-character key. The code is drawn by the plugin on your server; your key is never sent to an outside QR service. Typing the key by hand is still there under "Can't scan?", with a Copy button, plus a Copy setup link button for password managers.
* Recovery codes can be copied, downloaded as a .txt file or printed. The browser asks before you leave the page until you tick "I have saved these codes", and a notice at the top of your profile points to them.
* Security: an authenticator code now signs you in only once. Before, the same six digits could be used again for about a minute and a half.
* On the login page, after you enter your password, your username stays filled in on the code step. WordPress cleared it, so you had to type everything again.
* New FAQ: how to set up two-factor and how to get back in if you lose your phone.
* Where you are already looking at a problem — malware the scan found, or a check that needs a server change — one line now says where to get hands-on help. If you have set a Support contact (for example the agency that looks after the site), it names them instead. Nothing is sent anywhere; these are ordinary links.
* Readme: a Need help? section — free support on the forum, and where to get hands-on help.

= 0.2.13 =
* Settings > Notifications has a "Send test email" button, so you can confirm your site delivers SecureLite's email now instead of waiting for the first summary. If sending fails, it shows the mailer's error.
* The daily summary now separates what was stopped from what was only logged. Requests seen while the firewall or rate limiting is in Monitor mode are no longer reported under "no action is needed"; the email says they were not blocked and where to switch to Block.
* Fixed: in WordPress Playground (and setups that pass your login cookie to the site's own requests), Attack Simulation reported the firewall, user-enumeration and upload checks as failed, because each test arrived logged in as you and administrators are never filtered. Test requests are now always treated as an anonymous visitor. The bot and user-enumeration checks also work where requests go through a browser, which cannot send a custom User-Agent and follows redirects itself.
* Attack Simulation's uploads check now recognises a hosting firewall that refuses PHP in uploads with a code other than 403 (such as LiteSpeed's 444): a harmless control request in the same folder tells a real PHP block apart from the host briefly blocking the test.

= Earlier versions =

0.2.13 was the first version published on WordPress.org. The versions below it were built before publication.

= 0.2.12 =
* SecureLite no longer writes .htaccess files. The uploads protection now shows the exact rule for Apache/LiteSpeed and for nginx to add yourself (or hand to your host), and recognises it — or an equivalent your host added — once it is there. Rules applied by an earlier version are left in place.
* Attack Simulation's "PHP execution blocked in uploads" check writes nothing: it requests a .php address in uploads that does not exist and reports whether the server refused it before WordPress ran.
* Every file and folder location is now resolved from WordPress functions (get_home_path(), plugin_dir_path(), wp_upload_dir(), content_url() and others) instead of internal constants, so sites with WordPress in its own subdirectory or a moved content folder are scanned and reported correctly. The site root's .htaccess and index.php are watched in the home folder, where WordPress keeps them.
* The folder earlier versions kept in uploads (Attack Simulation samples) is removed on update.

= 0.2.11 =
* Malware scan now compares every WordPress core file with the official checksums from WordPress.org. Any PHP file added to wp-admin or wp-includes, and any changed core file, is reported as Critical; an unknown PHP file in the site root is reported, and Critical if it also matches a malware pattern. Found on a real hacked site: nine web shells in the site root and in wp-includes/js that the previous scan never looked at.
* Scanner hits in wordpress.org plugins are checked against that plugin's official release. Files identical to the release are cleared (stock elFinder, phpunit and similar library code was being reported as a backdoor); changed or added files are raised to Critical. Premium and custom plugins are marked as not verifiable.
* Genuine WordPress files from another release are no longer reported as malware. When new WordPress files were copied over an old install, an update stopped half way, or PHP's OPcache is still running the old version, core files are compared with the version written on disk, then with the newest release and the releases this site ran before; matching files are grouped into one plain finding ("an update did not finish", "left over from WordPress X") instead of one Critical per file. A file at a genuine WordPress path with altered content is still Critical.
* PHP files with unusual extensions (.php56, .php8, .PhP7 …) are now scanned.
* Packed payloads wrapped in another call before the decoder, such as eval(implode(…, gzinflate(base64_decode(…)))), are now Critical instead of Suspicious.
* The dashboard says when a scan stopped at its time or file limit, so a partial scan is never read as an all-clear.
* Attack Simulation on hosts with their own firewall (LiteSpeed, Imunify360, ModSecurity): WordPress now tags its answers to the simulation's probes, so an answer from the host is recognised. A probe the host refused (for example HTTP 444) is reported as blocked by your hosting server instead of failed; a dropped connection or a page-cache answer is reported as could not be tested, with the reason, and no longer shows an Enable & re-test button that could not change anything. Previously these hosts showed three failures on first run.
* Attack Simulation's brute-force check now still tests the lockout when the host refuses its test logins, cuts them off early, or this site's own address is a trusted IP. It runs SecureLite's lockout inside WordPress instead, from a reserved documentation address (192.0.2.0/24) so your own address is never locked, and confirms the lock trips at your limit and holds against a different username and against a correct password. Previously this check was skipped on those hosts, and its message suggested the host was already blocking bots, which a host filter only partly does.
* A failed brute-force check no longer offers Enable & re-test when login protection is already on.

= 0.2.10 =
* Fixed: Regenerate keys and salts could write a key containing "$" followed by a digit in a way that broke wp-config.php with a syntax error, taking the site offline. Keys are now written literally, and every wp-config.php change is checked to be valid PHP before it is saved — an edit that would not parse is refused.
* Security: SecureLite no longer copies wp-config.php anywhere. Edits to it (the file-editor switch, the trusted-IP line, Regenerate keys and salts) are written in place, read back and checked, and the original is restored from memory if the write did not land exactly. Every backup copy left by earlier versions — beside wp-config.php, under wp-content/securelite-backups or under uploads — is deleted on update.
* Attack Simulation never writes a PHP file. The malware-scanner check tests the real signatures and scan coverage against samples held in memory; the uploads check confirms SecureLite's rule is present and proves the server obeys .htaccess in uploads using a plain-text file. The configuration-backup check is removed, as there are no backups to expose.
* Rate-limiter and crawler-cache transients now use the plugin's full prefix.
* The "recovery codes running low" notice appears only on the Dashboard, your profile and SecureLite's screens.

= 0.2.8 =
* Security: the per-address lockout did not hold. WordPress's own password check replaced SecureLite's refusal, so a locked address saw the "too many failed attempts" message but could still sign in with the right password, or keep guessing under a different username. A locked address is now refused for the whole lockout window, whatever the password or username. The per-username lock is unchanged: the right password from another address still gets in.
* "PHP execution blocked in uploads" can now be fixed from the Verification screen with Enable & re-test, which writes the uploads rule and re-runs the check. If the rule is already there but PHP still runs, the result says your server is ignoring .htaccess and what to change, instead of sending you back to apply it again.
* Fixed: an uploads .htaccess holding only an empty SecureLite block, left behind after deactivating an older version, counted as protection. The check then blamed the server for ignoring .htaccess and hid the fix button. SecureLite now looks for the actual rule, and deactivating no longer leaves an empty block (or an empty file) behind.
* Fixed: the uploads rule included "Options -Indexes", which returns a 500 error for every image in uploads on hosts that don't allow that directive. It is removed, the rule now also works on Apache 2.2, and sites that already applied the old rule get the new one automatically.
* Attack Simulation now runs live: each attack goes out one at a time and you watch every protection answer, with a progress bar and the result appearing on each row. When it finishes the results stay on screen in the same design, with Enable & re-test on anything that can be fixed and a print/save button; the saved report uses the same layout. Enable & re-test now re-runs the same live view, so you watch the fix turn green.
* Repeat offenders are locked out longer. An address locked again within a day waits at least 1 hour, and after that at least 24 hours, so a bot that returns whenever a lock lifts gets a handful of guesses a day instead of hundreds. A person who mistypes once still waits only the normal window, and signing in successfully clears the address's history. Username locks never escalate.
* A repeat offender posting to the login form is refused with HTTP 429 and a Retry-After header before WordPress does any login work, which saves server resources under a sustained attack. A first-time lockout still shows the normal login screen.
* The lockout message now says how long login is paused, instead of "try again later", and links to a help page on getting back into your own site. It shows no recovery details itself, because attackers see it too, and it reads the same for an address lock and a username lock.
* Attack Simulation's brute-force check now also tries a fresh username from the locked address, and fails if that attempt is not refused, so this kind of gap cannot pass the check again.
* Security: with "Behind a proxy/CDN" on, a forwarded IP header was believed from any connection, so an attacker could send a fake X-Forwarded-For and dodge the lockout, or claim a trusted IP. Forwarded headers are now only read when the connection comes from a trusted proxy: your private network, Cloudflare's edges (new preset), or addresses you list. X-Forwarded-For is read from the right, so the address a client claims for itself is never taken on trust.
* Sites that already had proxy mode on get the Cloudflare preset switched on during the update, so visitors keep their real addresses.
* The settings screen shows which address SecureLite sees you connecting from and where it read it, and warns when Cloudflare traffic arrives with proxy mode off. Both problems also appear as posture findings.
* Fixed: in block mode the firewall could refuse an editor's or author's post that mentioned `javascript:`, `onclick=` or `document.cookie`, losing the draft. Content saved through wp-admin, admin-ajax or the REST API by users who can edit posts is no longer signature-matched; their URLs, cookies and uploads still are.
* Fixed: any form field containing the text "wp-config.php" was treated as a traversal attack. It now only matches when the whole value is a path to the file.
* Firewall log entries now record the role of the user who tripped them.
* One click to add your IP to wp-config.php as the lockout escape hatch. wp-config.php is backed up first, the change is read back to confirm it landed, and an existing SECURELITE_ALLOW_IP line is added to rather than duplicated. If the file cannot be written, the message says why — locked permissions, the file not found, or a definition SecureLite should not rewrite — and gives you the line to add by hand. Deactivating removes the line and reactivating puts it back, like SecureLite's other wp-config.php changes.
* SecureLite refuses to trust a Cloudflare address, whether from that button or typed into Trusted IPs, because it is shared by huge numbers of visitors. It tells you to set up proxy mode instead.
* Three ways back in after a lockout — a wp-config.php line with your current IP already filled in, a folder rename, and a WP-CLI command — are now on the Support screen and one click away under Login protection. They are also emailed to you once, the first time you save with a lockout feature on, and the save message tells you it was sent.
* SecureLite now shows an admin notice and stops loading, instead of causing a fatal error, if the server is later moved to a PHP or WordPress version older than it supports.
* Recovery → Reset passwords now shows exactly whose passwords it will reset, with a count and the usernames in the confirmation. When you are the only administrator it says so instead of reporting "Reset 0 password(s)", and links to your profile to change your own password.
* Security: resetting a password now also signs that account out everywhere and deletes its application passwords, which keep working for the REST API after a password change. It can email each account a link to choose a new password, and says plainly if the server could not send mail.
* Requires WordPress 6.2 or newer.

= 0.2.7 =
* SecureLite now removes what it added. Deactivating the plugin takes back the two changes it makes outside its own database — the rule in your uploads .htaccess and the DISALLOW_FILE_EDIT line in wp-config.php — and activating it again puts them back exactly as they were. Uninstalling removes them for good.
* It only ever undoes its own work. A DISALLOW_FILE_EDIT line that was in wp-config.php before you installed SecureLite is restored to its original text rather than deleted, and one that another plugin manages is not touched at all.
* Your settings, trusted IPs and security log are never touched by deactivation. Deactivating a plugin is how people troubleshoot, and it should not cost them their configuration.
* Security: the per-username lockout could be used against you. Anyone who knew an administrator's username could hold that account shut for everyone not on the trusted-IP list — including the real administrator, on mobile data, who then could not log in to add their address. The username lock is now decided after the password has been checked: a wrong password is refused exactly as before, and a correct one gets in and clears the lock. Guessing gains an attacker nothing, and someone who already has your password was never what this counter was protecting you from.
* A per-username lock is now capped at 30 minutes however long your lockout window is set. It is the one counter a stranger can drive up deliberately, so its duration is not theirs to choose.
* The system report now shows both lock durations.

= 0.2.6 =
* The system report on the Support screen now answers "why was I not locked out?" — it shows your own address and whether it is trusted, the live failure counts against their thresholds, when the current window opened, and when any active lock expires.
* The report also lists every plugin that has a hand in your login, in the order they run. A second security plugin answering the login before SecureLite is the quiet cause of half the reports that a lockout does nothing, and it was previously invisible.
* Added a Common problems entry for the same question, with the four causes in the order they turn out to be true.
* Fixed: the report still quoted the old rate-limiting defaults (block mode, 120 requests a minute) rather than the ones shipped since 0.2.2.

= 0.2.5 =
* Settings switches are now toggles rather than checkboxes, so the state of each protection reads at a glance.
* The theme and plugin file editor setting now detects when another plugin already controls it. Rather than showing a switch that would change nothing, it locks, shows what is actually true on your site, and explains where to change it.

= 0.2.4 =
* Added email notifications, sent by your own site with no external service involved. A daily summary plus an immediate email for two findings only: malware detected, or a watched file changed.
* SecureLite never sends one email per blocked request. That traffic is counted and summarised, never itemised, and the summary reports numbers of addresses rather than lists of them.
* On a quiet day, no summary is sent. An email that says nothing happened is how people learn to ignore a sender.
* Immediate alerts are limited to one per hour and only fire for a finding that is new — a condition that is still true tomorrow is not a new alert.
* Notifications can be set to summary-plus-alerts, alerts only, or off entirely. The local security log keeps recording either way.

= 0.2.3 =
* Two-factor authentication can no longer be switched on by ticking a box. You must enter a code your authenticator app produced, and if it is not accepted nothing changes and you stay signed in.
* Two-factor now issues ten single-use recovery codes at setup, shown once, stored hashed. Any of them will sign you in if you lose your phone, and you are warned when three or fewer remain.
* The setup secret is now kept between page loads, so scanning the QR code and then reloading the page no longer silently invalidates it.
* Changing your login URL is now proved before it is kept: the new address is requested over loopback, and if it does not return a login form the setting switches itself back off and tells you why. The new address is also emailed to the site administrator.
* Login slugs that collide with an existing page, post or category are refused, along with slugs under three characters.
* Attack Simulation gained a fourteenth check: it plants an inert file in the configuration backup directory, asks the server for it, and fails if the server hands it over.

= 0.2.2 =
* Security: wp-config.php backups were written next to wp-config.php in the site root, where a default server configuration serves them as plain text. They are now kept under wp-content in a protected directory with an unguessable filename, only the three most recent are retained, and any backup left in the site root by an earlier version is deleted automatically on update.
* Fixed: being asked for a two-factor code counted as a failed login, so users with two-factor enabled could be locked out of their own site while entering the correct password. Wrong authenticator codes now have their own, more forgiving budget.
* Fixed: retrying while locked out extended the lockout by the full window each time.
* Verified search-engine crawlers (Google, Bing, Yandex, Baidu, DuckDuckGo, Apple) are no longer rate limited. Each is confirmed by forward-confirmed reverse DNS, so a spoofed user-agent gains nothing. robots.txt and sitemaps are always served.
* Rate limiting now ships in monitor mode, and the default allowance is 240 requests per minute rather than 120. A per-IP cap also counts everyone sharing one address, so the log should be reviewed before it starts turning requests away.
* SecureLite now refuses to edit wp-config.php at all if it cannot write a backup first.

= 0.2.1 =
* SecureLite now runs entirely on your own site. The optional cloud transport has been removed along with its settings, so the plugin makes no outbound connections of any kind.
* Added a trusted-IP allowlist (exact address or CIDR, IPv4 and IPv6) exempting the brute-force lockout and rate limiter.
* Added the SECURELITE_ALLOW_IP wp-config constant so an administrator who is locked out can recover with file access alone.
* Added a tenth verification probe that plants an inert malware sample and confirms the scanner flags it, then removes it.
* Fixed: the rate limiter accepted an unvalidated authentication cookie name as proof of login.
* Admin interface refinements and cache-busted stylesheets.

= 0.2.0 =
* Added the request firewall (SQL injection, XSS, directory traversal, scanner signatures) with monitor and block modes.
* Added malware, JavaScript-injection and database scanning.
* Added the executable-upload virtual patch.
* Added rate limiting and Heartbeat API throttling.
* Added the hidden login URL, uploads hardening, post-hack recovery toolkit and Run Attack Simulation.

= 0.1.0 =
* Initial release: login hardening, TOTP two-factor, signal collection, file-integrity monitoring, posture scoring, heartbeat.
