WordPress powers 43% of all websites on the internet — which makes it the #1 target for automated attacks. In 2025 alone, Wordfence blocked over 90 billion malicious requests targeting WordPress sites. Plugin vulnerabilities, exposed configuration files, and brute-force attacks account for the vast majority of WordPress compromises.
This checklist covers every actionable security step you can take to harden your WordPress installation, with copy-paste commands for each item. We've organized it from most critical to least critical so you can prioritize effectively.
Before starting this checklist, run a free scan with AI QA Monkey's WordPress Security Scanner to identify your most urgent vulnerabilities. It checks for plugin CVEs, wp-config.php exposure, xmlrpc.php risks, and 30+ more issues in 60 seconds.
Core WordPress Hardening (Steps 1-8)
1. Update WordPress Core, Themes & Plugins CRITICAL
Outdated software is the #1 attack vector. 61% of hacked WordPress sites were running outdated core or plugins at the time of compromise.
# Enable automatic updates for minor releases (add to wp-config.php)
define('WP_AUTO_UPDATE_CORE', 'minor');
# Update via WP-CLI
wp core update
wp plugin update --all
wp theme update --all
2. Protect wp-config.php CRITICAL
This file contains your database credentials, authentication keys, and security salts. If exposed, an attacker has complete access to your database.
# .htaccess — Block access to wp-config.php
<Files wp-config.php>
Order Allow,Deny
Deny from all
</Files>
# Nginx equivalent
location ~* wp-config\.php {
deny all;
return 404;
}
Bonus: Move wp-config.php one directory above your WordPress root. WordPress automatically checks the parent directory.
3. Disable xmlrpc.php CRITICAL
xmlrpc.php enables XML-RPC protocol for remote publishing. Attackers exploit it for brute-force amplification — a single system.multicall request can test hundreds of passwords simultaneously.
# .htaccess — Block xmlrpc.php
<Files xmlrpc.php>
Order Deny,Allow
Deny from all
</Files>
# Nginx
location = /xmlrpc.php {
deny all;
return 403;
}
# Or disable via functions.php
add_filter('xmlrpc_enabled', '__return_false');
4. Disable File Editing in Dashboard HIGH
WordPress allows editing theme and plugin files directly from the admin dashboard. If an attacker gains admin access, they can inject malware through the built-in editor.
# Add to wp-config.php
define('DISALLOW_FILE_EDIT', true);
# Also prevent plugin/theme installation from dashboard
define('DISALLOW_FILE_MODS', true);
5. Change the Default Database Prefix HIGH
The default wp_ prefix makes SQL injection attacks easier because attackers know the exact table names.
# In wp-config.php (set BEFORE installation)
$table_prefix = 'x7k9_'; // Use a random prefix
# For existing installations, use WP-CLI:
wp db query "RENAME TABLE wp_posts TO x7k9_posts;"
# Then update wp-config.php and the options/usermeta tables
6. Set Proper File Permissions HIGH
# Set correct permissions
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
# Restrict wp-config.php
chmod 400 wp-config.php
# Restrict .htaccess
chmod 444 .htaccess
7. Disable Directory Browsing HIGH
Directory listing exposes your file structure, plugin names, and potentially sensitive files.
# .htaccess
Options -Indexes
# Nginx
autoindex off;
8. Remove WordPress Version Number MEDIUM
# functions.php — Remove version from head and feeds
remove_action('wp_head', 'wp_generator');
# Remove version from scripts and styles
function remove_wp_version_strings($src) {
global $wp_version;
parse_str(parse_url($src, PHP_URL_QUERY), $query);
if (!empty($query['ver']) && $query['ver'] === $wp_version) {
$src = remove_query_arg('ver', $src);
}
return $src;
}
add_filter('script_loader_src', 'remove_wp_version_strings');
add_filter('style_loader_src', 'remove_wp_version_strings');
Access Control & Authentication (Steps 9-14)
9. Limit Login Attempts CRITICAL
WordPress has no built-in login rate limiting. Without it, attackers can try unlimited passwords.
# Using Limit Login Attempts Reloaded plugin (recommended)
# Or add to functions.php:
function limit_login_attempts($user, $username, $password) {
$ip = $_SERVER['REMOTE_ADDR'];
$transient = 'login_attempts_' . md5($ip);
$attempts = get_transient($transient) ?: 0;
if ($attempts >= 5) {
return new WP_Error('too_many_attempts',
'Too many login attempts. Try again in 15 minutes.');
}
set_transient($transient, $attempts + 1, 900); // 15 min lockout
return $user;
}
add_filter('authenticate', 'limit_login_attempts', 30, 3);
10. Change the Default Login URL HIGH
Moving /wp-admin and /wp-login.php to a custom URL stops 99% of automated brute-force bots.
# Using WPS Hide Login plugin, or manually:
# .htaccess — Redirect wp-login.php to custom URL
RewriteRule ^my-secret-login$ /wp-login.php [L]
# Block direct access to wp-login.php
<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from 192.168.1.0/24 # Your IP range
</Files>
11. Enforce Strong Passwords HIGH
# functions.php — Force strong passwords for all users
function enforce_strong_password($errors, $update, $user) {
$password = isset($_POST['pass1']) ? $_POST['pass1'] : '';
if (!empty($password) && strlen($password) < 12) {
$errors->add('weak_password',
'Password must be at least 12 characters.');
}
return $errors;
}
add_action('user_profile_update_errors', 'enforce_strong_password', 10, 3);
12. Disable User Enumeration HIGH
Attackers can discover valid usernames via ?author=1 or the REST API.
# .htaccess — Block author enumeration
RewriteCond %{QUERY_STRING} ^author=([0-9]*)
RewriteRule .* - [F,L]
# Disable REST API user endpoint for non-authenticated users
add_filter('rest_endpoints', function($endpoints) {
if (!is_user_logged_in()) {
unset($endpoints['/wp/v2/users']);
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
}
return $endpoints;
});
13. Implement Two-Factor Authentication HIGH
Even with strong passwords, credentials can be phished or leaked. 2FA adds a second layer that stops 99.9% of automated attacks.
Recommended plugins: Two Factor Authentication (official WordPress plugin), WP 2FA, or Google Authenticator.
14. Set Proper User Roles MEDIUM
Follow the principle of least privilege. Content writers should be Authors, not Administrators. Review all user accounts quarterly and remove inactive ones.
File & Database Security (Steps 15-19)
15. Block Access to Sensitive Files CRITICAL
# .htaccess — Block access to sensitive files
<FilesMatch "(\.env|\.git|\.sql|\.bak|\.log|debug\.log|error_log|readme\.html|license\.txt)$">
Order Allow,Deny
Deny from all
</FilesMatch>
# Block wp-includes direct access
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
16. Secure the wp-content/uploads Directory HIGH
Prevent PHP execution in the uploads directory — a common malware injection point.
# wp-content/uploads/.htaccess
<Files "*.php">
Order Allow,Deny
Deny from all
</Files>
# Nginx
location ~* /uploads/.*\.php$ {
deny all;
return 403;
}
17. Secure the Database HIGH
# wp-config.php — Use a dedicated database user with minimal privileges
# Grant only: SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP
# Never use root for WordPress
# Regenerate security keys (visit this URL):
# https://api.wordpress.org/secret-key/1.1/salt/
# Then paste the output into wp-config.php
18. Disable PHP Error Display MEDIUM
# wp-config.php
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', true); // Logs to wp-content/debug.log
# .htaccess
php_flag display_errors Off
php_flag log_errors On
19. Add Security Headers MEDIUM
# .htaccess — Essential security headers
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:;"
Monitoring & Maintenance (Steps 20-25)
20. Install a Web Application Firewall HIGH
A WAF blocks malicious requests before they reach WordPress. Options include Cloudflare (free tier), Sucuri Firewall, or Wordfence (plugin-based).
21. Enable Automatic Backups HIGH
Backups are your last line of defense. Use UpdraftPlus, BlogVault, or WP-CLI with cron:
# Cron job for daily database backup
0 3 * * * wp db export /backups/db-$(date +\%Y\%m\%d).sql --path=/var/www/html
# Cron job for weekly full backup
0 4 * * 0 tar -czf /backups/full-$(date +\%Y\%m\%d).tar.gz /var/www/html
22. Monitor File Changes MEDIUM
File integrity monitoring detects unauthorized changes to core files, plugins, and themes — often the first sign of a compromise.
# WP-CLI — Check core file integrity
wp core verify-checksums
# Check plugin integrity
wp plugin verify-checksums --all
23. Audit Plugins Regularly MEDIUM
Remove unused plugins (even deactivated ones). Check each plugin's last update date — plugins not updated in 2+ years are a risk. Use AI QA Monkey's WordPress Scanner to check for known CVEs in your installed plugins.
24. Implement Login Activity Logging MEDIUM
Track who logs in, from where, and when. Use WP Activity Log or Simple History plugin to maintain an audit trail.
25. Run Regular Security Scans LOW
Schedule weekly scans with AI QA Monkey's WordPress Security Scanner. It checks for plugin vulnerabilities, exposed files, admin enumeration, xmlrpc.php risks, and 30+ more issues — all for free.
Scan Your WordPress Site Now
Free WordPress security scan — checks plugins, wp-config, xmlrpc, and 30+ vulnerabilities in 60 seconds.
Scan WordPress NowFrequently Asked Questions
What are the most critical WordPress security steps?
The most critical steps are: 1) Keep WordPress core, themes, and plugins updated, 2) Protect wp-config.php from public access, 3) Disable xmlrpc.php, 4) Use strong passwords and limit login attempts, 5) Install a WAF, and 6) Run regular security scans.
How do I protect wp-config.php?
Add a <Files wp-config.php> deny rule to your .htaccess file. You can also move wp-config.php one directory above your WordPress root — WordPress will automatically find it there.
Should I disable xmlrpc.php?
Yes, unless you specifically need it for Jetpack, the WordPress mobile app, or XML-RPC pingbacks. It's commonly exploited for brute-force amplification attacks.
How often should I scan my WordPress site?
Scan after every plugin/theme update, at least weekly for production sites, and immediately after any suspicious activity. Use AI QA Monkey's free WordPress Security Scanner for instant results.
- Free WordPress Security Scanner — plugins, wp-config, xmlrpc, and 30+ checks
- WordPress Malware Removal — step-by-step cleanup guide
- Hardening wp-config.php — essential security constants
- WordPress Hardening Roadmap 2026 — 30-60-90 day plan