WordPress core is maintained carefully and patched quickly. Most compromised WordPress sites get in through something around it: an outdated plugin, a reused admin password, a forgotten test install, or a backup sitting in the web root. This checklist works through those weak spots in order of impact, with the exact settings and snippets to apply. Most of it takes an afternoon, and the rest becomes routine maintenance.
Key takeaways
- Most compromised WordPress sites get in through outdated plugins, reused passwords, forgotten installs or exposed backups, not core.
- Turn on automatic updates for core, plugins and themes, and delete any plugins and themes you do not use.
- Use strong, unique passwords and two-factor authentication for every administrator, as WordPress core does not include 2FA.
- Automate off-site backups of the database and wp-content, keep several generations and test a restore.
1. Updates: the biggest single win
1. Keep core updating automatically. Minor (security) releases install automatically by default. To also allow major releases, add this to wp-config.php:
define( 'WP_AUTO_UPDATE_CORE', true ); // or 'minor' for security releases only
Never set AUTOMATIC_UPDATER_DISABLED to true. The WordPress docs strongly discourage it, because it also stops security releases.
2. Turn on plugin and theme auto-updates. In Plugins > Installed Plugins, use "Enable auto-updates" for each plugin (or the bulk action), and do the same under Appearance > Themes. For sites managed in code, a must-use plugin can switch them on:
<?php
// wp-content/mu-plugins/auto-updates.php
add_filter( 'auto_update_plugin', '__return_true' );
add_filter( 'auto_update_theme', '__return_true' );
If a plugin is business-critical and fragile, leave it on manual updates, but update it within days of a security release, not months.
3. Delete what you don't use. A deactivated plugin is still code on your server, and vulnerable files can still be requested directly. Delete inactive plugins and all themes except your active theme and one default theme as a fallback.
4. Only install from trusted sources. That means WordPress.org or well-known commercial vendors. "Nulled" (pirated) premium plugins frequently come with backdoors.
5. Watch for abandoned plugins. If a plugin hasn't been updated in a long time or was closed on WordPress.org, plan a replacement.
2. Logins and accounts
6. No "admin" username, and few administrators. Create a separate administrator account with a non-obvious username, then remove or demote legacy accounts. Give editors and authors the lowest role that lets them do their job.
7. Strong, unique passwords from a password manager. Credential stuffing (trying passwords leaked from other sites) works because people reuse passwords.
8. Two-factor authentication for every admin. WordPress core doesn't include 2FA, so use a reputable plugin (TOTP apps or security keys) or your SSO provider. The WordPress docs also point to passkeys as a phishing-resistant option and suggest enrolling at least two authenticators per admin, so losing one phone doesn't lock you out.
9. Rate-limit the login and XML-RPC endpoints. Bots hammer wp-login.php and xmlrpc.php around the clock. Rate-limiting at the edge (Cloudflare, your host's WAF) is best. On Nginx:
# In the http {} block
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=10r/m;
# In the server {} block
location = /wp-login.php {
limit_req zone=wplogin burst=5 nodelay;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php-fpm.sock; # match your PHP-FPM socket
}
If only a few people log in from fixed IPs, restrict wp-login.php to those IPs instead.
10. Disable XML-RPC if you don't need it. Its system.multicall method lets attackers try many passwords in one request. If you don't use Jetpack, the WordPress mobile app or a remote publishing tool, block it:
# .htaccess (Apache)
<Files "xmlrpc.php">
Require all denied
</Files>
# Nginx
location = /xmlrpc.php { return 403; }
If you do use it, rate-limit it with the same zone as the login page.
3. Files and configuration
11. Disable the built-in file editor. If an admin account is compromised, the theme and plugin editor is the quickest way to plant code. Add to wp-config.php:
define( 'DISALLOW_FILE_EDIT', true );
This removes the editor screens for every user. It won't stop malicious uploads, so it complements the other steps rather than replacing them.
12. Set sane file permissions. The WordPress hardening guide recommends:
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.php # or 400, depending on your host's setup
Only wp-content/ (uploads, cache) needs to be writable by the web server. Core files and plugins should be owned by your user account, not by the web server user. Never use 777.
13. Protect wp-config.php. Block direct web access. Apache, at the top of .htaccess:
<Files "wp-config.php">
Require all denied
</Files>
14. Stop PHP from running in uploads. Attackers who sneak a file into wp-content/uploads/ want to execute it. Block PHP there:
location ~* ^/wp-content/uploads/.*\.php$ {
return 403;
}
On Apache, place a .htaccess file inside wp-content/uploads/:
<FilesMatch "\.(php|phtml|phar)$">
Require all denied
</FilesMatch>
15. Remove leftover files. Delete wp-config.php.bak, backup.zip, db.sql, old installs in /old/ or /test/, and phpinfo.php files. See exposed .env, .git and backup files for blocking rules and how to check.
16. Turn off debug output in production. WP_DEBUG_DISPLAY should be false. If you log errors with WP_DEBUG_LOG, the default location is wp-content/debug.log, which is publicly readable unless you block it. Pass a path outside the web root instead:
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', '/home/youruser/logs/wp-debug.log' );
4. HTTPS and headers
17. Force HTTPS everywhere and make sure both the WordPress Address and Site Address under Settings > General start with https://. Fix any certificate errors and mixed content.
18. Send security headers. At minimum HSTS, X-Content-Type-Options: nosniff, Referrer-Policy, and frame-ancestors (or X-Frame-Options) to stop clickjacking on your login page. Configs are in our security headers guide. A strict Content Security Policy is harder with WordPress, because many plugins print inline scripts. Start in report-only mode.
5. Backups and monitoring
19. Automate off-site backups and test a restore. Back up both the database and wp-content/ on a schedule, store copies off the server (a host snapshot alone isn't enough if the account is compromised), and keep several generations, so you have a copy from before an infection that went unnoticed for weeks. A backup you've never restored is a guess.
20. Watch for changes. Use a security plugin or server tooling to alert you to file changes, new administrator accounts, and modified core files. WP-CLI can verify core files against the official checksums:
wp core verify-checksums
wp plugin verify-checksums --all
Any file reported as modified or added in core directories needs a closer look.
A quick monthly routine
| Task | Time |
|---|---|
| Confirm updates applied; review plugins with pending updates | 5 min |
| Review admin users; remove anyone who has left | 5 min |
Run wp core verify-checksums |
1 min |
| Check last backup succeeded; test-restore quarterly | 5 min |
| Re-scan headers, certificate and exposed files | 2 min |
Frequently asked questions
Do I need a security plugin?
Not strictly. Everything above can be done in configuration. A good security plugin makes 2FA, login rate limiting and file-change alerts easier, especially if you don't have server access. Pick one well-maintained plugin rather than stacking several that overlap.
Should I change the database table prefix from wp_?
The WordPress hardening guide mentions it as a way to block some automated SQL injection attacks that assume the default. It's easy on a new install and fiddly on an existing one. Patching vulnerable plugins matters far more, so do that first.
Should I hide the WordPress version or rename wp-admin?
Hiding the version or moving the login URL cuts down log noise from dumb bots. It doesn't stop a targeted attacker, because WordPress is easy to fingerprint in other ways. Treat these as optional extras after the steps above.
Is shared hosting less secure?
It can be, if the host doesn't isolate accounts well. A good managed WordPress host adds server-level firewalls, malware scanning and automatic updates. Whatever the hosting, plugin hygiene and strong logins are still your job.
What to do next
Work through sections 1 and 2 today. Updates and logins account for most compromises. Schedule the file and header changes for your next maintenance window. To check your headers, TLS certificate and exposed files and see which technologies your site exposes, run a free audit. If you think the site may already be compromised, go straight to signs your website was hacked.
Sources
Written by the MakeItFlow team
We build the website audit these guides are based on. Every fact is checked against the primary sources listed above . How we research and check
Check your own site in 30 seconds
Run a free audit covering speed, SEO, DNS, email authentication and security headers — and get a prioritised fix list.