Lockdown Ledger
20 subscribers
16 photos
2 links
Battle-tested security hardening checklists and SOPs for your sites. Copy-paste frameworks to lock down WordPress, servers, and access -- step by step, nothing skipped.
Download Telegram
File Permission Audit SOP
Run on any server you inherit or after a suspected breach.

— Step 1: Directories to 755, files to 644. Run find . -type d -exec chmod 755 {} \; then find . -type f -exec chmod 644 {} \;.
— Step 2: Lock wp-config.php to 640 (or 600 if PHP runs as owner). Never 644 on shared hosting.
— Step 3: Verify ownership. Web files owned by the app user, never root and never the web server user as owner.
— Step 4: Hunt for 777. find . -perm -o+w -type f — anything world-writable is a backdoor waiting to happen.
— Step 5: Confirm uploads/ can't execute PHP. Add a deny rule for .php in that directory.

Run this every time.
2FA Enforcement Rollout SOP
Use when mandating two-factor across a team, not just suggesting it.

— Step 1: Pick TOTP or hardware keys. Disable SMS — SIM-swap defeats it.
— Step 2: Set a grace window. 7 days from first login to enroll, enforced by plugin policy.
— Step 3: Force enrollment by role. Require it for Administrator and Editor first; expand to all roles after.
— Step 4: Generate and store recovery codes offline. Test one to confirm it consumes correctly.
— Step 5: Block the grace bypass. After day 7, unenrolled accounts get login-locked, not warned.
— Step 6: Audit monthly. Pull a list of accounts without an active 2FA secret and remediate.

Run this every time.
Least-Privilege Role Cleanup SOP
Run quarterly on every WordPress install.

— Step 1: Count your Administrators. More than 2-3 on a normal site is a finding, not a feature.
— Step 2: Demote content people. Writers get Author, reviewers get Editor. Nobody publishes copy from an Admin account.
— Step 3: Remove edit_files, install_plugins, and update_core from any custom role that doesn't deploy.
— Step 4: Set DISALLOW_FILE_EDIT to true in wp-config.php — kill the in-dashboard code editor entirely.
— Step 5: Delete dormant accounts. No login in 90 days = disable, then remove after review.
— Step 6: Reassign orphaned content before deletion so nothing breaks.

Run this every time.
Neighbor spotlight: @HandshakePapers. They go deep on SSL / HTTPS — the kind of channel you actually keep notifications on for.
Login Lockout Policy SOP
Configure on every site that has a wp-admin login.

— Step 1: Set the threshold. 5 failed attempts, then a 20-minute lockout. Escalate repeat offenders to 24 hours.
— Step 2: Lock by username AND IP. Attackers rotate IPs, so per-account counting matters more.
— Step 3: Mask the error. Never reveal whether the username or the password was wrong.
— Step 4: Rename or protect wp-login.php at the server level to cut bot volume before it hits PHP.
— Step 5: Whitelist your office and VPN egress IPs so you don't lock yourself out.
— Step 6: Alert on 50+ lockouts in an hour — that's an active campaign, not noise.

Run this every time.
WAF Rule-Tuning SOP
Do this after deploying any web application firewall.

— Step 1: Start in log/detection mode for 7 days. Never go straight to block on a live store.
— Step 2: Enable the OWASP Core Rule Set at paranoia level 1, then raise it only if false positives stay low.
— Step 3: Review the anomaly-score log. Tune individual rule exclusions, don't disable whole categories.
— Step 4: Add virtual patches for known plugin CVEs you can't update immediately.
— Step 5: Rate-limit /wp-admin, /wp-login.php, and the REST API /users endpoint specifically.
— Step 6: Switch to blocking mode, then re-run a baseline scan to confirm legit traffic still passes.

Run this every time.
REST API Lockdown SOP
Run on every WordPress site — the API is open by default.

— Step 1: Test exposure. Hit /wp-json/wp/v2/users — if it returns names and slugs, you're leaking your login usernames.
— Step 2: Require authentication on the users endpoint via a rest_authentication_errors filter for unauthenticated requests.
— Step 3: Don't blanket-disable the API — Gutenberg and many plugins need it. Scope restrictions to sensitive routes.
— Step 4: Remove author enumeration from the front end too. Block ?author=1 redirects at the server.
— Step 5: Verify usernames differ from display names. Same value = handed attackers half the credential.

Run this every time.
Database & Secrets Hardening SOP
Apply during every new-site provisioning.

— Step 1: Set a custom table prefix at install. Not wp_, and not a guessable word — use a random short string.
— Step 2: Give the WordPress DB user only the rights it needs: SELECT, INSERT, UPDATE, DELETE. Drop DROP, GRANT, and FILE in production.
— Step 3: Rotate all eight wp-config.php salts and keys. Pull fresh ones from the official secret-key API.
— Step 4: Move wp-config.php one directory above webroot if your stack allows it.
— Step 5: Bind MySQL to localhost. Confirm port 3306 isn't reachable from the public internet.
— Step 6: Verify backups encrypt the dump, not just the transport.

Run this every time.
Uploads Directory Hardening SOP
Do this on every site that accepts file uploads.

— Step 1: Block PHP execution in wp-content/uploads/. The classic backdoor is a .php disguised as an image landing here.
— Step 2: For Nginx: location ~* /uploads/.*\.php$ { deny all; }. For Apache: a .htaccess denying .php, .phtml, .phar.
— Step 3: Validate uploads by content, not extension. Check magic bytes, not just .jpg.
— Step 4: Strip EXIF and rename files to random tokens on upload to kill path-guessing.
— Step 5: Disallow double extensions like shell.php.jpg.
— Step 6: Verify. Drop a test .php in uploads, request it, confirm it downloads as text — never executes.

Run this every time.
WP-Cron Hardening SOP
Run on every production WordPress site for reliability and DoS resistance.

— Step 1: Disable pseudo-cron. Set DISABLE_WP_CRON to true in wp-config.php — every page load triggering cron is a load and abuse vector.
— Step 2: Schedule a real system cron hitting wp-cron.php at a fixed interval, every 5-15 minutes.
— Step 3: Block public access to wp-cron.php at the server, allowing only localhost.
— Step 4: Audit scheduled events with WP-CLI wp cron event list — orphaned plugin hooks pile up here.
— Step 5: Set ALTERNATE_WP_CRON only as a fallback, never as the default.

Run this every time.
Server Access Hardening SOP
Run before putting any web server into production.

— Step 1: Disable password SSH. Set PasswordAuthentication no and use keys only.
— Step 2: Disable root login. PermitRootLogin no, then sudo from a named user.
— Step 3: Move SSH off port 22 to cut log noise — defense in depth, not a real control.
— Step 4: Restrict by source. Firewall SSH to your VPN or a bastion host, never 0.0.0.0/0.
— Step 5: Use per-person keys, not one shared key. Revoking access means removing one line.
— Step 6: Audit authorized_keys quarterly. Remove keys for people who left.

Run this every time.
Plugin Vetting SOP
Run before installing any new plugin or theme.

— Step 1: Check last-updated date. Untouched in 12+ months = abandoned, treat as a liability.
— Step 2: Cross-reference the slug against a CVE database. Known unpatched vulnerability is an automatic no.
— Step 3: Verify install count vs. review quality. High installs hide that it's still a single-maintainer project.
— Step 4: Read what capabilities it requests. A contact form asking for install_plugins is a red flag.
— Step 5: Never install nulled or pirated plugins — they're the single most common malware vector.
— Step 6: Stage it first. Install on a clone, diff the filesystem, then promote to production.

Run this every time.