User Tools

Site Tools


security:hardening

# Security Hardening

## WordPress — Public File Exposure

### Problem Wordfence flags “Critical | Public Files” when these files are publicly accessible: - `license.txt` — reveals WP version - `wp-config-sample.php` — shouldn't be public - `readme.html` / `readme.[hash].html` — reveals WP version - `error_log` — exposes internal paths and PHP errors - `xmlrpc.php` — brute force / DDoS attack vector

### Fix applied 2026-05-18 (all 17 sites) 1. Deleted `license.txt`, `wp-config-sample.php`, `readme*.html`, `error_log` from all webroots 2. Added `xmlrpc.php` block to `.htaccess` on all sites (kaburu.co already had it) 3. Installed mu-plugin `remove-sensitive-files.php` on all sites — auto-removes sensitive

 files after any WP core update so they never come back

### mu-plugin location `wp-content/mu-plugins/remove-sensitive-files.php` on every managed site. Auto-loaded by WordPress, no activation needed. Hooks `upgrader_process_complete` and fires on `core` updates only.

### .htaccess xmlrpc block (added 2026-05-18) — ⚠️ PROVEN DEAD CODE ON LITESPEED

The original 2026-05-18 fix used an Apache-style `.htaccess` block:

``` # Block xmlrpc <Files xmlrpc.php>

Order Deny,Allow
Deny from all

</Files> ```

This never actually worked. LiteSpeed silently ignores Apache 2.2 `<Files>` / `Order Deny,Allow` syntax in `.htaccess`. Verified 2026-08-13: claybusters.scot had the block but `POST /xmlrpc.php` still returned HTTP 200. Wordfence's WAF was the only thing actually blocking xmlrpc attacks the whole time.

### ✅ Real fix applied 2026-08-13 — vhost context block (all 30 WP sites)

Replaced the dead `.htaccess` block with a LiteSpeed-native vhost context (exact-path, not regex — regex form is unreliable on LiteSpeed):

``` context /xmlrpc.php {

allowBrowse             0
accessControl {
  deny *
}

} ```

Rolled out via `scripts/estate-vhost-xmlrpc-block.sh` (same proven pattern as the debug.log rollout). Result: 28 sites added, 2 already had it (kaburu.co, rf.kaburu.co), 0 failed. Full LiteSpeed restart (`lswsctrl stop && start`). Verified per-site at origin (`curl –resolve SITE:443:49.13.202.144`) → HTTP 403 on all WP sites.

Edge cases (both fine): - `chippy.kaburu.co.uk` → 301 (redirect-only alias → thechippyvan.co.uk, which is 403) - `llmtest.kaburu.co` → 404 (xmlrpc not reachable; test-site vhost quirk, non-exploitable)

Pre-flight verified 2026-08-13: nothing legit uses xmlrpc.php — MainWP no longer uses xmlrpc SSO (zero dashboard-IP traffic across weeks of logs), and all xmlrpc hits were bot traffic (Azure/DO/Oracle cloud IPs).

### Sites covered (25 — full fleet as of 2026-07-31) 24hrresponse.com, aberdeenrda.co.uk, bankhousecatering.co.uk, billing.myretonmarquees.co.uk, chippy.kaburu.co.uk, claybusters.scot, dm-ph.com, doctorfin.co.uk, friendscic.org, ggsgenerators.co.uk, jafricasafari.com, kaburu.co, kaburu.co.uk, kaburusvr.uk, l8.kaburu.co.uk, l8waterhygiene.co.uk, llmtest.kaburu.co, longniddrybowlingclub.com, longniddrybowlingclub.co.uk, myretonmarquees.co.uk, pilates-edinburgh.co.uk, rf.kaburu.co, test-md.kaburu.cc, touchwell.co.uk, womenunlimited.africa

## WordPress — Debug Log Exposure (wp-content/debug.log)

### Problem `wp-content/debug.log` is written by WordPress when `WP_DEBUG_LOG=true` is set in `wp-config.php`. Can leak full request/response payloads, database errors, stack traces, user data, installed plugin paths.

### Defence-in-depth (applied 2026-07-31) Three layers, cheapest → most reliable:

1. `WP_DEBUG_LOG=false` in wp-config.php (eliminates source). Flipped on every site 2026-07-31. 2. .htaccess Log File Protection `<FilesMatch>` — present on 23/25 sites. DOES NOT WORK on LiteSpeed (Apache `<Files>`/`<FilesMatch>` ignored on OLS). 3. Vhost context block — the ONLY reliable block on LiteSpeed. Added to all 25 sites 2026-07-31:

 ```apache
 context /wp-content/debug.log {
   allowBrowse             0
   accessControl {
     deny *
   }
 }
 ```
  1. Appended to each `/usr/local/lsws/conf/vhosts/{site}/vhost.conf`
  2. Backups at `vhost.conf.bak-20260731-0501`
  3. Requires full LiteSpeed restart (`lswsctrl fullrestart`) — graceful SIGUSR1 does NOT pick up new contexts.
  4. Verified: 23/25 sites return HTTP 403 for debug.log; 2 (friendscic.org, llmtest.kaburu.co) return 404 (no file on disk = block never matches; equally safe).
  5. Belt-and-braces with Wordfence WAF (which also blocks the literal filename by name match).

Steve's rule 2026-07-31: “if WAF ever stops, we become exposed” — now mitigated by vhost context block.

## CyberPanel — Port Lockdown

- Port 8090 (CyberPanel): allow 100.64.0.0/10 (Tailscale), DROP rest — applied 2026-05-17 - Port 8081 (pdns API): allow 127.0.0.1, DROP rest — applied 2026-05-17 - Port 22 (SSH): allow Tailscale, DROP rest — applied 2026-05-17 - Rules persisted to /etc/iptables/rules.v4

## Pending

- [ ] Hetzner snapshot automation (manual snapshot done 2026-05-17) - [ ] TrueNAS offsite backup - [ ] FTP disabled / SFTP enforced - [ ] Hermes self-monitoring heartbeat (if Z840 goes down) - [ ] ufw proper firewall ruleset - [ ] CyberPanel backup verification - [ ] WordPress per-site backup plugin - [ ] Wordfence — investigate rainbowvapes.co.uk (High | Error), touchwell.co.uk (High | Server State)

security/hardening.txt · Last modified: (external edit)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki