What a WordPress Security Audit Actually Is (and Is Not)
A WordPress security audit is a fixed list of checks with pass criteria, run the same way every time, that ends in a written score. It is not a malware scan (that is one input to it), and it is not a plugin dashboard showing a green shield. If the procedure changes depending on who runs it, you have a poke-around, not an audit.
Why does the distinction matter to your bottom line? Because risk is lopsided. Patchstack recorded 11,334 new vulnerabilities across the WordPress ecosystem in 2025, up 42% on 2024. Ninety-one percent were in plugins, 9% in themes, and six were in WordPress core, all rated low. Nearly half (46%) had no patch available on the day they were disclosed. An audit built around those numbers spends its time on your plugin list and your ability to detect and recover, not on core.
Twelve checks, six groups, one table row per check: what to look at, the tool or command, what pass means, and how bad a failure is. You need SSH or WP-CLI for about half; the rest work from the dashboard and a browser. The severity scale we use:
- Critical: an attacker could take over the site, or you could not recover it. Fix this week.
- High: a known, commonly exploited weakness. Fix this month.
- Medium: raises risk or blinds you to an incident. Fix in the next maintenance cycle.
- Low: hygiene. Batch it.
Checks 1-2: Inventory (Do You Know What Is Running?)
Most audits fail here first, quietly. You cannot secure software you do not know you have, and the numbers say plugins are where the risk lives.
Check 1 is versions: core, PHP, every plugin, every theme. WordPress officially supports only the latest release. The security team backports fixes to older branches as a courtesy, with no promise on timing, and dropped versions 4.1 through 4.6 entirely in July 2025. At the time of writing the current branch is 7.0 (7.0.4 shipped August 12, 2026) with 7.1 due within days. On the PHP side, 8.1 stopped receiving security fixes at the end of 2025 and 8.2 loses them at the end of 2026.
Abandoned and unused code is check 2. WordPress.org flags any plugin not tested against the last three major releases and eventually closes plugins that stay unmaintained. Our threshold is stricter: no author update in 12 months means it goes on a replacement list. Installed-but-inactive plugins get deleted, because inactive code still sits on disk and can still be reached by anyone who knows the path.
| # | What to check | Tool or command | Pass criteria | Severity if failing |
|---|---|---|---|---|
| 1 | Core, PHP, plugin, theme versions | wp core version, wp plugin list --update=available, hosting panel for PHP |
Core on the current branch; PHP 8.2+ (8.3+ preferred); no pending update that closes a disclosed vulnerability | High (Critical if a pending update patches a disclosed flaw, or PHP is 8.0 or older) |
| 2 | Abandoned and unused plugins and themes | wp plugin list --status=inactive, Last updated date on wordpress.org |
Nothing untouched by its author for 12+ months; no inactive plugins; one inactive default theme at most | High if the abandoned plugin has a known CVE; Medium otherwise |
wp core version
wp plugin list --update=available --format=table
wp plugin list --status=inactive --field=name
wp theme list --status=inactive --field=name
Cross-reference pending updates against a vulnerability feed (Patchstack, WPScan, or Wordfence Intelligence). A pending feature update is housekeeping. A pending update that closes a disclosed flaw is Critical, because the median heavily targeted vulnerability in 2025 was being exploited within five hours of disclosure.
Checks 3-5: Access (Who Can Get In, and How?)
Every account that can log in is a door, and stolen or guessed credentials remain the cheapest way through one. Broken access control and privilege escalation together made up 77% of the attacks Patchstack blocked in 2025, so this group is about limiting how far any single door leads.
Check 3 lists every administrator and makes you justify each one by name. Former contractors, temp accounts from a migration, and the agency that built the site three years ago get removed or downgraded. Check 4 is credentials: two-factor authentication enforced (not merely available) for administrators and editors, plus a minimum password length the site refuses to go below. Check 5 covers the side doors: application passwords (available to every user since WordPress 5.6) and XML-RPC (still enabled by default) both authenticate outside the login form. Turn off whatever nothing depends on.
| # | What to check | Tool or command | Pass criteria | Severity if failing |
|---|---|---|---|---|
| 3 | Administrator accounts | wp user list --role=administrator |
Every admin is a named, current person; no shared logins; no account named admin | Critical if an unknown admin exists (possible compromise); High for surplus admins |
| 4 | 2FA and password policy | Wordfence Login Security, WP 2FA, or your host’s SSO; check role enforcement | 2FA required for admin and editor roles; 14+ character minimum enforced | High |
| 5 | Application passwords and XML-RPC | Users > Profile; curl -X POST https://example.com/xmlrpc.php |
Application passwords disabled unless a named integration needs them; xmlrpc.php returns 403 | Medium (High if brute-force attempts show in logs) |
Two short additions close check 5 on most sites: a filter in a must-use plugin, and a web server rule for xmlrpc.php.
add_filter( 'wp_is_application_passwords_available', '__return_false' );
<Files xmlrpc.php>
Require all denied
</Files>
An unknown administrator is not a hardening finding, it is an incident. If check 3 turns one up, stop here and switch to the process in our guide to fixing a hacked WordPress site, because every check you run afterward may be reporting on code the attacker already controls.
Checks 6-7: Integrity (Have the Files Been Tampered With?)
Integrity checks answer one question: is the code on disk the code the authors shipped? WP-CLI can compare your install against wordpress.org checksums in under a minute, which makes this the highest-value part of a self-run audit.
Check 6 runs wp core verify-checksums and wp plugin verify-checksums --all. Core verification flags modified, missing, or unexpected files in wp-admin and wp-includes. Plugin verification only covers plugins hosted on wordpress.org; premium plugins publish no checksums, so for those you fall back to file modification dates and a scanner. Check 7 covers file permissions and the wp-config.php constants that stop a logged-in attacker from turning dashboard access into code execution.
| # | What to check | Tool or command | Pass criteria | Severity if failing |
|---|---|---|---|---|
| 6 | Core and plugin file integrity | wp core verify-checksums, wp plugin verify-checksums --all |
Both return Success; any flagged file has a documented explanation | Critical for unexplained modified or added files |
| 7 | Permissions and wp-config hardening | find, stat wp-config.php, wp config get DISALLOW_FILE_EDIT |
Directories 755, files 644, wp-config.php 400 or 440; DISALLOW_FILE_EDIT true; no PHP under wp-content/uploads | High |
wp core verify-checksums
wp plugin verify-checksums --all
find . -type d ! -perm 755 | head
find . -type f ! -perm 644 | head
find wp-content/uploads -name "*.php" -type f
wp config get DISALLOW_FILE_EDIT
If the last command errors out, the constant is missing. Add it above the stop-editing comment in wp-config.php:
define( 'DISALLOW_FILE_EDIT', true );
Files are only half of integrity. Compromises also persist in wp_options and orphaned postmeta, which is why we treat WordPress database maintenance as a security task rather than a performance chore.
Checks 8-9: Perimeter (What Can a Stranger Reach?)
Perimeter is everything a visitor sees before logging in. Two checks: is something filtering hostile requests, and what is exposed that should not be.
Check 8 is the firewall and login rate limiting. Cloudflare’s managed WordPress rules, Wordfence in extended protection mode, or your host’s edge WAF all count, but the pass condition is that it is on and demonstrably seeing traffic. Do not treat “my host has a WAF” as a pass on its own: Patchstack found hosting-level defenses blocked only 12% of the actively exploited vulnerabilities it tested. Check 9 is TLS, headers, and exposed files: HSTS present, readme.html (which reveals your version) blocked, no wp-config.php backup copies or debug.log reachable, and no directory listing on uploads.
| # | What to check | Tool or command | Pass criteria | Severity if failing |
|---|---|---|---|---|
| 8 | WAF and login rate limiting | Firewall dashboard; try six wrong passwords on wp-login.php from a test IP | Firewall active with recent blocked-request events; lockout after 5 failed logins | High |
| 9 | TLS, HSTS, exposed files, directory listing | curl -sI against the URLs below; a header scanner such as Mozilla HTTP Observatory |
HTTP redirects to HTTPS; Strict-Transport-Security header present; readme.html, debug.log, wp-config.php.bak return 403 or 404; /wp-content/uploads/ does not list files | Medium (High if debug.log or a config backup is readable) |
curl -sI https://example.com/ | grep -i strict-transport-security
curl -sI https://example.com/readme.html | head -1
curl -sI https://example.com/wp-content/debug.log | head -1
curl -sI https://example.com/wp-config.php.bak | head -1
curl -sI https://example.com/wp-content/uploads/ | head -1
A readable debug.log is worse than it sounds. It routinely contains full server paths, plugin names with versions, and database errors that quote table names, which hands an attacker most of check 1 for free.
Checks 10-12: Monitoring and Recovery (Would You Know, and Could You Come Back?)
Prevention fails sometimes. The last three checks decide whether a failure costs you an afternoon or a month, and they are the checks most sites have never done.
Check 10 asks whether anything tells you when files change or when someone logs in as an administrator. Wordfence’s scheduled scan email and login notifications cover both on a small site; on a larger one, alerts need to land somewhere a human reads within a day. Check 11 is uptime monitoring from outside your server, alerting to a phone rather than an inbox nobody watches at 3 a.m. Check 12 is recovery: a backup exists, a copy lives somewhere other than the server it protects, and you can name the date you last restored one. A backup you have never restored is a hypothesis, not a backup.
| # | What to check | Tool or command | Pass criteria | Severity if failing |
|---|---|---|---|---|
| 10 | File change and admin login alerts | Wordfence scan schedule and alert settings, or your host’s file monitoring | Scan runs at least daily; alerts reach a monitored address; new-device admin logins notify | Medium |
| 11 | External uptime monitoring | Any external monitor (UptimeRobot, Better Stack, host-provided) at 5-minute intervals or faster | Active, alerting by SMS or push, checking a page that renders content rather than only returning 200 | Medium |
| 12 | Backups exist, are offsite, and restore | Backup plugin or host dashboard; restore log | Daily database and weekly full-file backups at minimum; one copy offsite (different provider or region); a restore test in the last 90 days with the date recorded | Critical if no offsite copy or no successful restore on record |
How to Score the Audit and Decide What to Fix First
Score by severity, not by count. Any single Critical failure means the audit fails, no matter how many of the other 11 checks pass. Beyond that, work the list in this order:
- Fix every Critical within days: unknown admins, unexplained file changes, missing offsite or untested backups, pending updates that patch disclosed flaws.
- Fix Highs within the month: outdated versions, abandoned plugins, missing 2FA, loose permissions, no firewall.
- Fold Mediums into the next scheduled maintenance pass.
- Within a tier, do the cheapest fix first. Adding DISALLOW_FILE_EDIT takes two minutes; replacing an abandoned form plugin takes an afternoon.
Record the date, the pass count out of 12, each failed check with its severity, who owns the fix, and a due date. An identical format every time is what makes the next WordPress security audit comparable to this one, and it is what a client, insurer, or compliance reviewer will actually ask to see.
How Often Should You Run a WordPress Security Audit?
Quarterly for most business sites. Monthly for anything with customer accounts, payments, or memberships, because a WooCommerce store carries more plugin surface and more to lose per day of undetected compromise. On top of the schedule, run the full 12 checks after any of these events:
- A hack or suspected compromise, once cleanup is complete
- A change of hosting provider or server
- A new agency, developer, or administrator being granted access
- A major WordPress release you have just moved to
- A vulnerability disclosure in a plugin you rely on, even after patching
The audit verifies your process; it does not replace it. Checks 1 and 10 in particular belong in a normal monthly maintenance routine, and the audit is where you find out whether that routine actually held.
What a Do-It-Yourself Audit Cannot See
An honest audit report includes its blind spots, and this one has four. First, zero-days and unpatched disclosures: with 46% of 2025’s vulnerabilities lacking a patch when they went public, your site can pass check 1 cleanly and still be exploitable that same afternoon. Second, server-level compromise on shared hosting: a neighbouring account, an outdated control panel, or a kernel flaw is invisible from inside WordPress and outside your power to fix. Third, premium plugin integrity, since there are no public checksums to verify against. Fourth, everything that happens between audits, which is exactly the gap monitoring exists to shrink.
What closes those gaps is not a longer checklist. It is a firewall with virtual patching that someone actually maintains, continuous file integrity scanning, and a person on the other end of the alerts. That is the shape of our WordPress security maintenance service, and it is what we recommend to anyone who runs this audit and finds Critical failures they do not have time to keep closed.
Your first move today takes 30 seconds: run wp user list --role=administrator (or open Users and filter by Administrator) and read every name aloud. If you cannot say who a person is and why they still need admin access, you have found your first Critical, and you already have the plan for it.
Frequently Asked Questions
Plan for 60 to 90 minutes with SSH and WP-CLI access, or two to three hours working only through the dashboard, hosting panel, and a browser. That covers the audit itself. Fixing what it finds is separate work, though most individual fixes take under 15 minutes.
No. A scanner such as Wordfence is one input to the audit, mainly for file integrity and malware signatures. It does not tell you whether your backups restore, whether former contractors still hold admin accounts, or whether your host exposes debug logs. Use the plugin scan as evidence, not as the verdict.
Stop the audit. Take a snapshot of the site as-is for forensics, change every credential, and switch to a cleanup process: scan, remove the malicious code, find the entry point, patch it, then harden. Finishing the remaining checks on a compromised site wastes time because the results may already be tainted.
Want this audit run for you every quarter?
Our security maintenance includes scheduled audits, Wordfence firewall management, file integrity monitoring, and backups we actually restore, with findings reported in plain language.