WordPress Security Hardening, Explained

What WordPress hardening covers, from security headers and file permissions to least-privilege access, and how to do it without breaking third-party services.

Published

What does WordPress hardening cover?

WordPress hardening is the set of configuration changes that shrink what an attacker can reach and limit what a stolen login can do. It covers security headers, HTTPS, file permissions and ownership, database privileges, and access control. It does not replace updates or monitoring.

Which security headers matter?

Start with two: one that forces HTTPS and one that restricts what code a page may run.

Per MDN, Strict-Transport-Security tells browsers that a host “should only be accessed using HTTPS,” and later attempts over plain HTTP are upgraded automatically. Once a browser has cached the policy, it “will not allow the user to bypass secure connection errors, such as an invalid certificate.” Browsers ignore the header when it arrives over plain HTTP, so the HTTP site should only redirect to HTTPS.

With includeSubDomains, the policy covers every subdomain, so a subdomain that can only be served over HTTP stops loading for anyone who has cached it. Confirm every subdomain serves HTTPS before adding it.

Content-Security-Policy “provides fine-grained control over the code that can be loaded on a site, and what it is allowed to do,” according to MDN’s CSP guide. A well-built policy limits what a script injected into a page is allowed to do. It is also the header most likely to break a working site, which is why the same guide advises testing a policy in report-only mode first: it shows what would have been blocked without blocking it.

What should file permissions and the database allow?

File permissions should let the web server read what it needs and write as little as possible. The WordPress hardening handbook lists 755 for directories and 644 for files, with the files owned by your user account rather than the web server’s. Ownership matters as much as the numbers: if the web server owns the files, 644 still lets it rewrite them.

For wp-config.php, which holds the database credentials, the handbook suggests 400 or 440. 400 works only when PHP runs as the file’s owner; otherwise use 440 with the web server’s group, or the site cannot read its own configuration.

The handbook applies the same idea to the database account, with a caveat. It says normal operation needs only “data read and data write privileges,” and that structural privileges such as DROP, ALTER, and GRANT could be revoked. It then recommends against doing so, because major core updates change the database schema, and asks for a tested backup plan if you revoke them anyway.

What do DISALLOW_FILE_EDIT and DISALLOW_FILE_MODS do?

Both are wp-config.php constants that remove the ability to change code from inside the admin. DISALLOW_FILE_EDIT turns off the plugin and theme file editor. DISALLOW_FILE_MODS goes further and blocks plugin and theme installs and updates from the admin, per the wp-config documentation.

DISALLOW_FILE_MODS also switches off WordPress’s automatic background updates, including core security releases, per the automatic updater’s source. A site that sets it needs its own release process for every update, including urgent ones; see managing WordPress updates safely.

The handbook notes that disabling the editor “will not prevent an attacker from uploading malicious files to your site.” These constants reduce the damage a stolen admin login can do. They do not stop an attacker who found another way in.

How should access to the site be controlled?

Give every account the least access that lets its owner do the job, and require a second factor on every account that can change the site, including the hosting control panel. Editors do not need administrator roles, and an outside vendor building a landing page does not need access to the whole site. The handbook calls enabling two-step authentication “a good idea” as an additional measure.

Accounts for former staff, contractors, and vendors stay active until someone removes them, so review access on a schedule. For how far lockdown can go on a regulated site, see WordPress security for financial services and healthcare sites.

How do you stop password-guessing attacks on the login page?

Limit how many login attempts the site accepts and, where the host allows it, do it before the request reaches WordPress. The WordPress handbook’s brute force guidance recommends rate-limiting login attempts at the edge (a WAF or CDN) or at the web server. A security plugin can throttle attempts when the host does not, but it runs inside WordPress and, in the handbook’s words, plugins “still execute within PHP and thus consume some resources under heavy attack.”

OWASP’s Authentication Cheat Sheet adds that the failed-login counter should be “associated with the account itself, rather than the source IP address,” so attempts spread across many addresses still count.

Should XML-RPC be turned off?

Yes, if nothing on the site uses it. The handbook’s brute force guidance calls xmlrpc.php a frequent brute-force target, “especially the system.multicall method,” and advises disabling it when unused. When something depends on it, such as Jetpack or the WordPress mobile apps, it advises restricting and rate-limiting it instead.

Should PHP be allowed to run from the uploads folder?

No. WordPress has to be able to write to the uploads folder so editors can add media, which makes it the obvious place for an attacker to drop a script. Configure the web server to refuse to run PHP there, in line with the hardening handbook’s general rule to “avoid allowing execute and write permissions to the extent possible.”

OWASP’s File Upload Cheat Sheet adds a second step. An attacker may try to upload a server configuration file such as .htaccess that changes how the folder handles files, so “disable per directory configuration overrides on upload directories at the web server level.”

Does a WordPress site need a web application firewall?

Yes, for any site where an incident would be costly. A managed WAF, from a provider such as Cloudflare or Sucuri or from the host, filters known bad IPs and automated login attempts at the edge, rate-limits the login and XML-RPC endpoints, and challenges suspicious requests, per the handbook’s brute force guidance. The handbook’s stated advantage: “traffic is blocked before reaching your server.”

A WAF does not patch the site or replace hardening, access control, and monitoring.

How should hardening changes be rolled out?

One change at a time, on a test copy first, with a way to undo each one. Several changes at once make it hard to tell which one broke something.

Tightening file permissions can stop WordPress from writing where it needs to, such as the uploads directory, so test an upload and an update after changing them. For headers, list the third-party services the site loads, run the strictest policy in report-only mode, read what it would have blocked, and adjust before enforcing. Repeat that whenever a service is added.

MDN notes that under a strict policy, scripts loaded by an allowed script fail unless the policy is built to trust them, and that allowlists of domains “often end up allowing unsafe domains.” On one healthcare research site, the services at stake were analytics, forms, and verification tools, and we built a security layer that kept them working; see automated security hardening for a healthcare research organization.

Record what changed, when, and why, so someone else can undo it later.

Does removing unused code count as hardening?

Yes. Every installed plugin and theme is code that has to be kept patched, and deactivating a plugin does not remove its files from the server. Removing it shrinks the surface without adding any new tooling.

Fewer plugins also limits a supply-chain risk that scanning and testing miss. Our post on why WordPress plugins get a bad rap describes how “someone bought 30 WordPress plugins from a legitimate company and backdoored every one of them.” To file monitoring, a malicious plugin update looks like any other update, and it passes testing if the site still works. What limits the damage is having fewer plugins, least-privilege access, and logs and backups to recover with.

How do you know hardening worked?

Check headers and TLS from outside the site, and permissions and core files on the server, after every release. A header scan shows which security headers are actually sent, a TLS scan shows the certificate and protocol setup, a permission audit shows who can write where, and wp core verify-checksums shows whether core files match WordPress.org.

A new plugin, a server change, or a policy loosened to admit a new tag can undo a header or a permission without anyone noticing, so repeat these checks on a schedule.

Already compromised?

Hardening a site that has already been hit starts with finding out how the attacker got in. Start with fixing a hacked WordPress site.

Talk to us about hardening your WordPress site.

Not sure what's hardened on your site?

Describe your hosting and who can log in. 84EM will tell you which controls are missing and how to roll them out without breaking the site.

Folks we've helped.