• Latest
  • Trending
  • All

WordPress Security Audit 2026: The 18 Checks That Block 90% of Automated Attacks

June 14, 2026
ssh command cheatsheet

SSH Command Cheatsheet: Connect, Keys, scp, Tunnels (2026)

June 16, 2026
chmod-chown-cheatsheet

chmod and chown Cheatsheet: Linux Permissions, Decoded (2026)

June 16, 2026
systemctl-journalctl-cheatsheet

systemctl + journalctl Cheatsheet: Services and Logs (2026)

June 16, 2026
grep-cheatsheet

The grep Cheatsheet: Search a File, Search a Tree (2026)

June 16, 2026
rsync-cheatsheet

The rsync Cheatsheet: Mirror, Sync, Copy Over SSH (2026)

June 16, 2026
curl-cheatsheet

curl Cheatsheet: Download Files and Test APIs (2026)

June 16, 2026
iptables-vs-nftables-cheatsheet cheatsheet

iptables vs nftables: Linux Firewall Cheatsheet, Side by Side

June 16, 2026
nmcli-cheatsheet cheatsheet

nmcli Cheatsheet: Wi-Fi and Network Connections From the Linux Terminal

June 16, 2026
powershell-networking-cheatsheet cheatsheet

PowerShell Networking Cheatsheet: Test-NetConnection, IP, DNS (2026)

June 16, 2026
tar command cheatsheet

The tar Command Cheatsheet: Create, Extract, Stop Guessing (2026)

June 16, 2026
Linux find command cheatsheet

The find Command Cheatsheet: Every Recipe You Actually Use (2026)

June 15, 2026
Linux networking commands cheatsheet, ip and ss

Linux Networking Commands in 2026: the ip and ss Cheatsheet

June 15, 2026
  • Online Tools
  • Network Tools
  • Developer Tools
  • Security Tools
Tuesday, June 16, 2026
  • Login
People Are Geek
  • Online Tools
  • Network Tools
  • Developer Tools
  • Security Tools
No Result
View All Result
People Are Geek
No Result
View All Result
Home Security Tools

WordPress Security Audit 2026: The 18 Checks That Block 90% of Automated Attacks

by People Are Geek
June 14, 2026
in Security Tools
0
0
SHARES
4
VIEWS
Share on FacebookShare on Twitter

Guide WordPress security · 12 min read · Updated May 2026

Ten years cleaning up hacked WordPress sites. The zero-days I’ve seen? I can count them on one hand. Almost every site I’ve untangled fell to boring stuff that had been sitting in the open for a decade: a missing security header, or an exposed readme.html, or a TLS certificate that quietly expired three days ago. The default admin username any bot reads straight off ?author=1. None of it clever. So here’s what I actually do when a site lands on my desk. These 18 checks, between them, swat away maybe 90 percent of the automated junk thrown at WordPress in 2026. Each one comes with the exact config line you paste into nginx, Apache or functions.php. Cold site, no prior hardening? You can knock the whole list out before lunch. Call it 90 minutes.

Table of contents

  1. The state of WordPress security in 2026
  2. HTTP security headers, the foundation
  3. TLS certificate hygiene
  4. WordPress version disclosure
  5. xmlrpc.php, REST users and default exposures
  6. User enumeration and login hardening
  7. Plugins, themes and the supply chain
  8. The full 18-point checklist
  9. FAQ

The state of WordPress security in 2026

WordPress still runs roughly 43 percent of the web in 2026, and honestly that’s the whole problem right there. Biggest target, most arrows. Look at it from the attacker’s side for a second: write one scraper that hammers /xmlrpc.php and /wp-login.php across the entire IPv4 range, leave it running a week, and you’ve poked a huge slice of the internet for free. Now flip it around. Close the eighteen tired old holes in this guide and that same attacker has to either find a real authenticated plugin bug or actually social-engineer somebody, and both of those cost a fortune next to a drive-by scan. You won’t be unhackable. Nobody is. You’ll just stop being worth the bother, and against automated scanners that’s about all you need.

Two things genuinely changed since 2023, and I’ve watched both land on real clients. AI doing the reconnaissance, for one: a bot scrapes an admin’s name off a leaked author archive, then spits out a spear-phish that’s good enough to fool a tired person at 5 p.m. The other is “form spam as a service.” I had a client once whose single unprotected contact form was relaying enough junk to basically pay some spammer’s hosting bill. Both of those reward the same dull discipline. Know what of yours is public. Then shut it.

Table mapping what automated attacks hit on WordPress to the audit check that blocks each one: xmlrpc.php, where system.multicall packs hundreds of password guesses into one request past rate limits, blocked at the web server (check 12); wp-login.php brute force across the whole IPv4 range, answered with 2FA on every admin plus fail2ban or login rate limits (17); author=1 leaking the admin username through a redirect, killed (16); the REST users endpoint handing back every publishing user in a single GET, locked for anonymous callers (13); generator meta, ver parameter and readme.html revealing the exact version and its matching CVEs, all three stripped (9 to 11); abandoned plugins, where most new WordPress CVEs land, covered by a quarterly inventory and a CVE feed (18); verdict band: left open the scan costs the attacker nothing at IPv4 scale, all 18 closed they need a real authenticated plugin bug or social engineering
What the drive-by scanners actually knock on, and the check that slams each door.
Recommended security gearWe may earn a commission, at no extra cost to you.
Yubikey Security KeyCheck price on Amazon →Password ManagerCheck price on Amazon →Usb Data BlockerCheck price on Amazon →Webcam Cover SlideCheck price on Amazon →

HTTP security headers, the foundation

Five minutes on a site? This is where I spend them. Headers cost nothing and, set right, they break nothing, and the browser does the enforcing for you on every visitor’s machine. My 2026 baseline is six of them. I want all six on every public page, no exceptions.

HSTS (Strict-Transport-Security)

HSTS is just you telling the browser “for this domain, plain HTTP is dead to you” for a set window. That kills the whole family of downgrade tricks on sketchy coffee-shop Wi-Fi, and it stops a stolen cookie getting replayed over an insecure link. I set it to a year, cover the subdomains, make it preload-eligible:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

Set this one at the web server (nginx add_header, Apache Header always set), not in a plugin. Plugins come and go, and I don’t want my transport security riding on whatever happens to be installed this month. Run it for a month with no HTTPS surprises, then submit the domain to hstspreload.org and it ships baked into every major browser.

Content-Security-Policy

CSP is the strongest XSS brake you’ve got, full stop. Lock it down and the browser flat-out won’t run a script or load a stylesheet from anywhere you didn’t put on the list. I’ll be honest though: getting there on an existing WordPress site is rarely a one-shot job, because old themes drag in resources from a dozen origins you forgot you were even using. Start strict, then loosen:

Content-Security-Policy: default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; script-src 'self'; frame-ancestors 'self'; base-uri 'self'; form-action 'self';

Do yourself a favor and run Content-Security-Policy-Report-Only for a couple of weeks before you flip it to enforcing. Report-only logs every violation and blocks nothing, so you get to see which third-party origins your site actually leans on. You find them in a log. Not in an angry email about the checkout being broken.

X-Frame-Options and frame-ancestors

This is your clickjacking guard. Two ways to set it: X-Frame-Options: SAMEORIGIN, or frame-ancestors 'self' inside your CSP. The CSP one is the modern way. The header is the old fallback for anything that still doesn’t speak CSP. So set both. They don’t conflict, and you’re covered either way.

The three “minor but free” headers

These I just paste in and forget. X-Content-Type-Options: nosniff stops the browser guessing a file’s type when it shouldn’t, which shuts a small-but-real XSS door. Referrer-Policy: strict-origin-when-cross-origin keeps you from leaking full URLs to every site you link out to. Then Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() switches off browser features a blog has no business touching. Grand total: about 200 bytes a response. Your privacy posture gets a quiet, free bump for it.

TLS certificate hygiene

A valid cert is the price of entry. One that keeps renewing itself? That’s the real tell someone’s actually watching the site. I’ve lost count of the times I got called in for an “outage” that was just a dead certificate. Box was perfectly secure. The auto-renewal had quietly choked on a Let’s Encrypt rate limit, or a botched DNS challenge. One memorable time, a password the host had changed without telling anyone. And the ending never varies. Every browser on every phone throws that big red warning, and traffic just bleeds out for hours while nobody notices.

So treat the cert as a thing you check, not a thing you install once and forget about. I look at the days remaining at least weekly with our SSL Certificate Checker or via SecurityWatch. And the trick that’s saved me more than anything else: two renewal triggers, not one. Run the Let’s Encrypt cron job, then put an external monitor on top of it, so when one fails the other screams. Got a pile of subdomains? A wildcard cert keeps your life simple, and staying on one CA across all of them turns the audit into a five-minute job instead of a scavenger hunt. One last thing for 2026. If TLS 1.3 isn’t your preferred protocol yet, you’re behind, and tossing HTTP/3 / QUIC on top is a nice win for the mobile crowd.

WordPress version disclosure

Hand an attacker your exact WordPress version and you’ve basically given them a shopping list. They pull up the matching CVEs faster than you can read this sentence. And WordPress gives that version away for free in a few spots. There’s a <meta name="generator" content="WordPress X.Y.Z"> tag on every single page, plus a ?ver= tacked onto every CSS and JS file it loads. Then /readme.html, sitting right at your document root. All of it has to go.

Kill the generator tag with a few lines in your theme:

// functions.php
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', function () { return ''; });

Strip the ?ver= off your assets with a filter:

add_filter('style_loader_src', 'pag_strip_ver', 9999, 2);
add_filter('script_loader_src', 'pag_strip_ver', 9999, 2);
function pag_strip_ver($src, $handle) {
    return remove_query_arg('ver', $src);
}

And /readme.html, core updates love to drop a fresh copy back in, so either delete it after every update or just block it at the server and stop thinking about it:

# nginx
location = /readme.html { deny all; }
# Apache
<Files "readme.html">Require all denied</Files>

xmlrpc.php, REST users and default exposures

xmlrpc.php is the old brute-force back door, and it’s nastier than it looks. It authenticates over an RPC protocol that sails straight past most rate-limiting plugins. Worse, its system.multicall method lets an attacker cram hundreds of password guesses into a single request, so your “5 failed logins and you’re locked out” rule never even fires. And it’s the engine behind the pingback DDoS amplification that once turned innocent WordPress sites into a botnet for hire. Unless you actually lean on the Jetpack mobile apps or remote publishing, shut it:

# nginx
location = /xmlrpc.php { deny all; return 403; }
# Apache
<Files "xmlrpc.php">Require all denied</Files>

Next, the one people forget: the REST endpoint /wp-json/wp/v2/users. Out of the box it cheerfully hands back every user who can publish, which means an attacker reads your admin username in a single GET request. No brute force needed, no guessing. They just ask, and WordPress tells them. Lock it for anyone who isn’t logged in:

add_filter('rest_endpoints', function ($endpoints) {
    if (!current_user_can('list_users')) {
        unset($endpoints['/wp/v2/users']);
        unset($endpoints['/wp/v2/users/(?P<id>[\\d]+)']);
    }
    return $endpoints;
});

One more freebie: open directory listings on /wp-includes/ and /wp-content/uploads/. If those are browsable, you’re handing over your whole file layout plus the versions of everything running, core and plugins and themes, basically a map of every door worth knocking on. Turn autoindex off globally, nginx (autoindex off;) or Apache (Options -Indexes). I also like dropping an empty index.html into the writable folders, so even a box the next person misconfigures shows a blank page instead of your laundry.

User enumeration and login hardening

The other big leak on a stock install is author-archive enumeration. Same problem as the REST one, different door. Someone visits https://yoursite.com/?author=1 and WordPress helpfully bounces them to /author/admin-login/, spelling your login name right out in the URL bar. Now they’ve got the username for free, and only the password stands between them and you. Slam that redirect shut:

add_action('template_redirect', function () {
    if (isset($_GET['author'])) {
        wp_redirect(home_url(), 301);
        exit;
    }
});

After that, login hardening is a short list I never skip. 2FA on every admin account, no exceptions, and the Two Factor plugin from the core team is the path of least resistance. A real password manager, whichever one (Bitwarden, KeePass, pick your poison), because they all beat reusing your email password, and reusing your email password is, hands down, the mistake I watch burn people the most. And rate-limiting on failed logins, since core flat-out won’t do it for you. Bolt on Limit Login Attempts Reloaded, or do what I prefer and kill the brute-force traffic at the edge with fail2ban before it ever reaches PHP.

Plugins, themes and the supply chain

Here’s where the fire actually is in 2026. Core bugs have gone scarce. The WordPress security team is genuinely good these days, so the attackers moved to where the wood is dry: your plugins and themes. Patchstack and Wordfence keep saying the same thing every quarter, that the overwhelming majority of new CVEs land on plugins, not core. A handful of habits cut that risk way down:

  • Minimise plugin count. Every plugin you install is another door someone else built into your house. I go through the list once a quarter and rip out anything I’m not actually using, because that “eh, might need it later” plugin sitting there deactivated and unpatched? That’s exactly the one that gets popped.
  • Prefer plugins with recent updates. No update in 18 months is a yellow flag for me. Hit 36 and it’s dead to me, I assume nobody’s home and go find an alternative that’s still being maintained.
  • Subscribe to a CVE feed. Patchstack, Wordfence and the WordPress vulnerability database all push RSS or JSON feeds. Wire one into Slack or your monitor so a critical advisory pings you the day it drops. Not three months later, when a scanner finds it already running on your live site.

Themes follow the same logic, plus one hard rule I’ll die on: never, ever hack on a theme directly. Use a child theme. Always. Your updates keep flowing, and six months out whoever audits the site (could well be you) can tell at a glance what’s custom and what came from upstream. Edit the parent theme directly and you’ve built the classic landmine. Site hums along fine, someone clicks “update theme,” and now everything’s on fire and nobody remembers what got changed.

The full 18-point checklist

Everything in one place. I run it at launch, then every quarter, then once more after any core update. That last pass is the one that catches the readme.html WordPress just snuck back in behind your back.

The 18 WordPress audit checks grouped by attack surface: six HTTP security headers (HSTS, Content-Security-Policy, X-Frame-Options or frame-ancestors, nosniff, Referrer-Policy, Permissions-Policy), two TLS hygiene checks (certificate over 30 days remaining with a renew alert, TLS 1.3 on and 1.0/1.1 off), three version disclosure checks (generator meta removed, ver parameter stripped, readme.html blocked), four default exposures (xmlrpc.php blocked, REST users endpoint locked, wp-includes and uploads directory listings off), two login checks (author redirect killed, 2FA on every admin) and one supply chain check (plugin and theme inventory reviewed in the last 90 days); chip colors mark severity high, medium or low if the check is missing
All 18 checks, sorted by the door each one closes. Red means fix it today.
#CheckSeverity if missing
1HSTS header with max-age >= 15552000 + includeSubDomainsHigh
2Content-Security-Policy at least at default-src ‘self’High
3X-Frame-Options: SAMEORIGIN or frame-ancestors ‘self’ in CSPMed
4X-Content-Type-Options: nosniffLow
5Referrer-Policy: strict-origin-when-cross-originLow
6Permissions-Policy with explicit deny on unused featuresLow
7TLS certificate with > 30 days remaining + auto-renew alertHigh
8TLS 1.3 enabled, TLS 1.0 / 1.1 disabledMed
9WordPress generator meta removedMed
10?ver= stripped from asset URLsLow
11readme.html deleted or blocked at web serverMed
12xmlrpc.php blocked (unless used by Jetpack)Med
13/wp-json/wp/v2/users blocked for unauthenticated callersHigh
14/wp-includes/ directory listing disabledHigh
15/wp-content/uploads/ directory listing disabledMed
16?author=N redirect blocked or rewrittenMed
172FA enforced on every administrator accountHigh
18Plugin and theme inventory reviewed last 90 daysMed

Want this scan automated?

SecuChecker throws all 18 checks at any URL in about 20 seconds, then hands you a posture score plus the exact fix for whatever it finds open. It’s free and it runs right in your browser. Never touches your server.

Run SecuChecker →

FAQ

How often should I run a security audit on a WordPress site?

Quarterly is my floor. Plus a pass after every core update, and any time you add or pull a plugin, since those are the moments things quietly change under you. Busy store where downtime costs real money? I’d go weekly and let SecurityWatch do the watching, so you don’t have to remember to.

Is HSTS preload safe for a small site?

Yes, but treat it like a one-way door, because it basically is. Once you’re on the preload list, crawling back to plain HTTP is slow and miserable, and removal takes weeks even when it goes smoothly. So run HSTS from your server config for a solid month first. Prove HTTPS never hiccups. Then submit. Don’t preload on day one and just hope.

Will blocking xmlrpc.php break Jetpack?

It can, yeah. You’ll lose the Jetpack mobile apps and a few remote-publishing bits. If you actually use those, don’t just nuke the file. Allow-list xmlrpc.php for the Jetpack IP ranges they publish in their docs, and you keep both. But if you’ve never once opened the Jetpack app or published remotely? Blocking it is the easy, correct call, and honestly you’ll never miss it.

Do I need a managed WAF if I do all this?

Need is a strong word. A WAF (Cloudflare, Sucuri, Wordfence Premium) buys you defence in depth, and where it really earns its keep is the zero-day plugin bug that drops in the gap between two of your audits, when you’d otherwise be sitting wide open. So think of it this way. The 18 checks are the work you have to do. A WAF is the seatbelt I’d add on any site where an hour of downtime genuinely hurts.

How do I rotate the admin password without breaking automation?

Stop sharing the admin login with your scripts. That’s the root of the pain right there. Make a dedicated automation user with the lowest role that actually does the job (nine times out of ten that’s Editor, not Administrator), point your CI or CMS automation at that account, and rotate the human admin password on its own schedule. Keep that interval sane too, somewhere around 90 to 180 days. Force a change every two weeks and I promise you it ends up on a sticky note under the keyboard.

My site already has a high SecuChecker score, what next?

Nice. Now stop staring at the score and start building for the day something gets through anyway, because eventually something will. Subscribe to a plugin CVE feed (Patchstack, Wordfence) so you hear about trouble early. Switch on file-integrity monitoring (Wordfence or iThemes Security) so you know the second a file changes that shouldn’t. And run automated daily backups to somewhere off the box, which is the boring one everybody skips until the day they’d have killed for it. A hardened site keeps people out. That stuff is what gets you back on your feet fast when one finally slips in.

Sources & further reading

  • WordPress, Hardening WordPress
  • OWASP, Top Ten

Related tools and resources

SecuChecker (one-shot WP audit) SecurityWatch (continuous monitoring) HTTP Headers Checker SSL Certificate Checker CSP Header Builder .htaccess Generator Robots.txt AI Crawler Blocker
ShareTweetPin
People Are Geek

People Are Geek

I'm Stephane, a network and systems engineer with over 15 years of hands-on experience on production infrastructure, virtualization (ESXi, Proxmox), networking, and self-hosting. Earlier in my career I built and ran a Linux resource site that became a well-known reference for sysadmins. Today I focus on cybersecurity, and I also work as a technical trainer, teaching networking and security to people who do it for a living. Everything on People Are Geek comes from real-world practice, not theory. I build every tool on this site myself, and I write about what I've actually deployed, broken, and fixed. If it's here, I've used it.

People Are Geek

Copyright © 2017 JNews.

Navigate Site

  • About PeopleAreGeek
  • Affiliate Disclosure
  • All Tools and Articles
  • Contact
  • Cookie Policy
  • Hyper-V Hub: Tools, Error Fixes and Lab Guides
  • Linux Hub: Cross-Distro Reference, Articles, Tools
  • Privacy Policy
  • Sample Page
  • Terms of Service
  • VMware vSphere & ESXi Hub: Tools, Error Fixes and Guides

Follow Us

Welcome Back!

Login to your account below

Forgotten Password?

Retrieve your password

Please enter your username or email address to reset your password.

Log In
No Result
View All Result
  • Online Tools
  • Network Tools
  • Developer Tools
  • Security Tools

Copyright © 2017 JNews.