Most WordPress security hardening checklists are ranked by how easy each step is to write about, not by how much risk it removes. That is why so many sites end up with a renamed login URL, a hidden version number, and an out-of-date contact form plugin that is the actual way in.
Here is the short version. Six measures remove most of the realistic risk: keep plugins patched on a schedule you actually hold to, remove the plugins you are not using, put two-factor on every administrator, take backups you have restored at least once, restrict file writes with DISALLOW_FILE_EDIT and sane permissions, and limit who holds an admin role. Everything else on the typical list is either a small bonus or an outage waiting for a Friday afternoon.
The rest of this article explains why that order, what each measure costs you in broken functionality, and which popular hardening steps to skip.
Why the standard hardening checklist misses
Patchstack’s State of WordPress Security in 2026 report counted 11,334 new vulnerabilities disclosed across the WordPress ecosystem during 2025, a 42% increase over the 7,966 counted in 2024. The split matters more than the total: 91% were in plugins, 9% in themes, and six were in WordPress core — all six rated low priority.
So core is not your problem. Your plugins are. A hardening checklist that spends ten items on core files and one line on “keep plugins updated” has the weighting backwards.
Two more numbers from the same report change how you should think about the work:
- The median time from disclosure to first exploitation attempt was about five hours for heavily targeted vulnerabilities. Roughly 45% were under attack within 24 hours, and 70% within seven days. A monthly patch window is not a patch window; it is a 30-day exposure window.
- Hosting-level defenses blocked only 12% of actively exploited WordPress vulnerabilities in Patchstack’s testing, rising to 26% across a wider set. The test covered internal host WAFs, Cloudflare, Imunify360 and ModSecurity. A WAF is worth having as a layer. It is not worth treating as a reason to delay updates.
Broken access control accounted for 57% of exploited vulnerabilities, with privilege escalation at 20% and local file inclusion at 10%. These are logic flaws in plugin code — an endpoint that forgets a capability check. No amount of file-permission tightening touches them. Patching does.
What to harden, and what each step breaks
The useful question for any hardening measure is not “is this more secure?” but “what does this stop, and what does it break?” Here is that trade-off for the measures that come up most often.
| Measure | What it actually prevents | What it breaks | Verdict |
|---|---|---|---|
| Patch plugins within 72 hours of release | The majority of real compromises | Occasional plugin conflicts — test on staging | Do this first |
| Delete unused plugins and themes | Vulnerable code that is installed but inactive is still reachable in some cases | Nothing, if genuinely unused | Do it |
| 2FA on all admin accounts | Credential stuffing and password reuse | Lockout if the admin loses their phone and has no recovery codes | Do it, with recovery codes stored |
DISALLOW_FILE_EDIT | An attacker with a stolen admin session editing theme files from the dashboard | Nothing — you lose the built-in code editor, which you should not be using anyway | Do it |
| File permissions 644 / 755, wp-config.php 440 | Cross-account writes on shared hosting, some upload exploits | Plugin installs may need FTP credentials if ownership is wrong | Do it |
| Limit admin-role accounts | Blast radius of any one compromised login | Minor friction for editors who were used to installing plugins | Do it |
| Rotate salts in wp-config.php | Stolen session cookies staying valid | Logs every user out, including customers mid-checkout | Do it — after an incident, or off-peak |
| Rename the login URL | Noise in your logs. Bots find it again | Breaks saved bookmarks, some plugin redirects, password reset flows | Optional, low value |
| Change the database table prefix | “At least some SQL injection attacks,” per WordPress docs | High risk on a live site — serialized data and hardcoded queries break | Only on a new install |
| Disable the REST API | Very little | The block editor, media library, WooCommerce admin, Yoast, Elementor | Don’t — restrict it instead |
DISALLOW_FILE_MODS | Plugin installs from a compromised dashboard | Blocks all plugin and theme updates, including security updates | Only with an external deploy pipeline |
| Hiding the WordPress version | Nothing measurable | Nothing | Skip it |
That last group is where most of the damage gets done. DISALLOW_FILE_MODS is the clearest example: it is on half the hardening lists on the web, and on a site without a Git-based deploy process it quietly stops the one activity that protects you most. A site that cannot update plugins is not hardened. It is frozen at the moment of its last patch, which — given the five-hour exploitation median above — is a worse position than an unhardened site that updates promptly.
The wp-config.php changes worth making
These are the constants that earn their place. Add them above the /* That's all, stop editing! */ line.
/* Remove the built-in theme and plugin file editors.
Equivalent to removing edit_themes, edit_plugins and
edit_files from every user. */
define( 'DISALLOW_FILE_EDIT', true );
/* Force the admin area and login over HTTPS. */
define( 'FORCE_SSL_ADMIN', true );
/* Minor core releases install themselves. This is the default,
but state it so a plugin cannot quietly change it. */
define( 'WP_AUTO_UPDATE_CORE', 'minor' );
/* Do not leak PHP errors to visitors. */
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_DISPLAY', false );On DISALLOW_FILE_EDIT, the WordPress documentation is honest about its limits: “This will not prevent an attacker from uploading malicious files to your site, but might stop some attacks.” That is the right framing for the whole exercise. These constants narrow what a compromised session can do. They do not stop the compromise.
Two constants you will see recommended that need more thought. WP_AUTO_UPDATE_CORE set to true enables major releases automatically — fine on a simple brochure site, risky on anything with custom code, because major versions are where things break. And AUTOMATIC_UPDATER_DISABLED turns updates off entirely, which only makes sense if something else is applying them. We go through the failure modes in detail in what actually breaks when you auto-update WordPress.
File permissions
WordPress documents one workable scheme: 755 on directories, 644 on files, and tighter on the config file.
find /path/to/wordpress/ -type d -exec chmod 755 {} \;
find /path/to/wordpress/ -type f -exec chmod 644 {} \;
chmod 440 /path/to/wordpress/wp-config.phpThe docs specify 400 or 440 for wp-config.php so that only your user and the web server can read it. If you keep a debug log, set it to 600. The common failure here is ownership rather than mode: if files are owned by a different user than the one PHP runs as, WordPress falls back to asking for FTP credentials on every plugin install. Fix ownership before you tighten modes.
Do not disable the REST API
This deserves its own section because it is the single most common way a hardening pass takes a site down.
The official WordPress REST API documentation is unambiguous: “You should not disable the REST API; doing so will break WordPress Admin functionality that depends on the API being active.” In practice that means the block editor loads blank or refuses to save, the media library stops working, and WooCommerce admin screens, Yoast, Elementor and Contact Form 7 all lose functionality, because they make REST calls from inside wp-admin.
What people are usually trying to stop is anonymous user enumeration — the fact that /wp-json/wp/v2/users returns names and slugs for authors who have published content, and that the slug is identical to the login name on a default install. That is a real, if modest, exposure. The fix is to require authentication rather than to switch the API off. The WordPress documentation supplies the pattern itself:
add_filter( 'rest_authentication_errors', function( $result ) {
if ( ! empty( $result ) ) {
return $result;
}
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_not_logged_in',
'You are not currently logged in.',
array( 'status' => 401 )
);
}
return $result;
} );Logged-in requests pass through, so the editor keeps working; anonymous external requests get a 401. If your site has a headless front end, a mobile app, or an integration that reads public endpoints, this will break it — restrict only the /wp/v2/users route in that case. And close the other door at the same time: blocking the REST endpoint achieves nothing if ?author=1 still redirects to the author archive and reveals the same slug.
The same reasoning applies to XML-RPC. Blocking xmlrpc.php is usually safe and removes a credential-stuffing target, but check first whether anything is using it — the WordPress mobile app, Jetpack, and some remote publishing and backup tools do.
Hardening will not clean an already-compromised site
This is worth stating plainly because we see it regularly. Hardening is preventative. Applied to a site that is already backdoored, it changes nothing except that you now feel safer — the backdoor was installed before the lock was fitted, and most of them do not depend on the dashboard, the login page, or XML-RPC to keep working.
If there is any sign of an existing compromise — unexpected admin users, search results in a language you don’t publish in, outbound spam, files with recent modification times you cannot account for — stop the hardening work and deal with that first. Our walkthrough of what to do in the first 60 minutes after a hack covers the triage order, and the Japanese keyword hack article goes through one specific infection end to end, including the reindexing work that follows.
If you are not sure which situation you are in, that uncertainty is itself the thing to resolve. Ask us for a security audit — we will tell you whether you are looking at a hardening job or a cleanup, before you spend money on either.
A rollout order that does not lock you out
Hardening causes outages mostly because it is done in one pass, on production, by someone who then closes the laptop. A sequence that avoids that:
- Before anything: take a backup and restore it somewhere. An untested backup is a guess. Every step below is reversible if you can restore; none of them are if you cannot.
- Audit accounts. Remove dormant admins, demote anyone who does not need the role, and check for accounts nobody recognises. This costs nothing and shrinks the attack surface more than any config change.
- Update everything, on staging first. Get current before you harden. Then decide the patch cadence you can genuinely hold — weekly beats monthly by a wide margin, given what the exploitation timing data shows.
- Delete what you are not using. Inactive plugins and themes are still code on disk.
- Add the wp-config constants. Low risk, immediate effect.
- Fix ownership, then permissions. In that order. Verify a plugin install still works afterwards.
- Enable 2FA — last, and with recovery codes saved somewhere other than the site. Have a second admin account with 2FA configured before you enable it on your own, so that a failed enrollment is an inconvenience rather than an emergency.
- Only then consider the optional items. REST restriction, XML-RPC blocking, login URL changes. One at a time, each with a tested rollback.
Keep a note of what you changed and when. When something breaks three weeks later — a form stops submitting, a plugin update fails silently — the first question is always what changed, and “we hardened the site last month” is not an answer anyone can work with.
What this is actually protecting against
Almost none of the attacks that take down small and mid-sized WordPress sites are targeted. They are automated scans against a list of known vulnerable plugin versions, running continuously against every WordPress site on the internet. The scan does not know or care who you are. It knows that version 3.4.2 of a plugin you installed four years ago has a broken access control flaw, and that your site is still running it.
That is why patch cadence outranks every configuration tweak, and why the plugin inventory matters more than the firewall. We go deeper into how that pipeline works — from disclosure to mass exploitation — in the plugin vulnerability pipeline.
Hardening is the cheap part. Keeping a site patched, week after week, when nothing appears to be wrong, is the part that actually requires someone to own it. If nobody at your company currently owns that, talk to us about a maintenance plan — the patch cadence is the product, and the hardening comes with it.
