
A WordPress security checklist is the fastest way to close the gaps that attackers actually exploit — not the exotic zero-days, but weak logins, exposed config data, outdated files, and default settings nobody bothered to change. Most successful attacks on WordPress sites come from a handful of well-known weaknesses. Here are 12 concrete steps, with code, to harden a site properly.
Why a WordPress Security Checklist Matters
WordPress powers a huge share of the web, which makes it a constant target for automated bots scanning for outdated plugins, weak passwords, and misconfigured servers. You don’t need to stop every theoretical attack — you need to close the common, cheap ones that bots probe for by default.
1. Disable File Editing from the Admin Dashboard
By default, any admin can edit theme and plugin files directly from wp-admin. If an attacker gets admin access, this becomes an instant path to executing arbitrary PHP. Turn it off in wp-config.php:
define('DISALLOW_FILE_EDIT', true);
2. Move or Restrict wp-config.php
wp-config.php holds your database credentials and secret keys. WordPress will read it one directory above the install root, so moving it out of the web root removes it from direct HTTP access entirely.
// .htaccess, as a fallback if you can't move the file:
<files wp-config.php>
order allow,deny
deny from all
</files>
3. Limit Login Attempts and Enforce Strong Passwords
Brute-force login attempts are one of the most common automated attacks. Rate-limit failed logins and force strong passwords for every role with dashboard access, not just admins.
// Example: reject weak passwords on registration/profile update
add_action('user_profile_update_errors', function ($errors, $update, $user) {
if (!empty($_POST['pass1']) && strlen($_POST['pass1']) < 12) {
$errors->add('pass', 'Password must be at least 12 characters.');
}
}, 10, 3);
4. Change the Default “admin” Username and Login URL
Never keep a user named admin — it’s the first guess in every brute-force script. Combine this with hiding the default /wp-login.php and /wp-admin paths behind a custom slug using a lightweight security plugin, or rewrite the route yourself at the server level.
5. Disable REST API User Enumeration
The default REST API happily lists registered usernames at /wp-json/wp/v2/users, handing attackers a ready-made list of login targets. Restrict it to authenticated requests only:
add_filter('rest_endpoints', function ($endpoints) {
if (isset($endpoints['/wp/v2/users'])) {
unset($endpoints['/wp/v2/users']);
}
if (isset($endpoints['/wp/v2/users/(?P<id>[d]+)'])) {
unset($endpoints['/wp/v2/users/(?P<id>[d]+)']);
}
return $endpoints;
});
6. Keep Core, Plugins, and Themes Updated
Most real-world WordPress breaches exploit a known, already-patched vulnerability in outdated software. Enable automatic minor core updates at minimum, and review plugin/theme changelogs regularly instead of updating blindly on a schedule.
// wp-config.php: enable automatic updates for minor core releases (default)
// and optionally for all core releases:
define('WP_AUTO_UPDATE_CORE', true);
7. Add Security Headers
Security headers instruct the browser to enforce protections against clickjacking, MIME sniffing, and some XSS vectors. Add them via functions.php or, better, at the server/CDN level:
add_action('send_headers', function () {
header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: strict-origin-when-cross-origin');
});
8. Set Correct File and Directory Permissions
Overly permissive file permissions let a compromised script write to files it shouldn’t touch. A safe baseline for most shared hosting setups:
// Directories: 755
find /path/to/wordpress/ -type d -exec chmod 755 {} ;
// Files: 644
find /path/to/wordpress/ -type f -exec chmod 644 {} ;
// wp-config.php specifically: 600 or 440, if your host allows it
chmod 600 wp-config.php
9. Disable XML-RPC If You Don’t Need It
XML-RPC is frequently abused for brute-force amplification (via system.multicall) and DDoS pingback attacks. Unless you rely on the WordPress mobile app or a service that specifically needs it, disable it:
add_filter('xmlrpc_enabled', '__return_false');
10. Take Automated, Offsite Backups
Backups don’t prevent an attack, but they’re what turns a disaster into an inconvenience. Automate them, store copies offsite (not just on the same server), and actually test a restore occasionally — an untested backup is a hope, not a plan.
11. Enforce HTTPS Everywhere
Serve the entire site over HTTPS and redirect all HTTP traffic. This protects login credentials and session cookies from being intercepted on the network, and it’s also a minor ranking factor.
// wp-config.php, if behind a reverse proxy/load balancer that terminates SSL:
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
$_SERVER['HTTPS'] = 'on';
}
12. Monitor for File Changes and Suspicious Logins
Detection matters as much as prevention. A file-integrity monitor that alerts on unexpected changes to core, plugin, or theme files — combined with login logging — means you find out about a breach in hours, not months. For more detail on official hardening recommendations, the WordPress Hardening Handbook is worth bookmarking as a reference alongside this checklist.
Wrapping Up
None of these 12 steps require exotic tools — most are a config change, a filter, or a habit. Start with the ones that take five minutes (disabling file editing, XML-RPC, and REST user enumeration) and work down the list. If you’re also exposing custom data through your own endpoints, pair this checklist with our guide on building a custom WordPress REST API endpoint to make sure your own routes are locked down too.