🛡️ WordPress 6.9 Security Guide: Protect Your Site from Hackers 2026
Complete security guide to prevent hacking, malware, and attacks. Learn hardening, firewall setup, PHP 8.3 security features, and monitoring. 50+ actionable steps to lock down your site.
After implementing this guide: 95%+ Protected
Blogs Team
Security Experts • 2026 Edition
🔰 Security Basics: First Line of Defense (Tips 1-5)
Keep Everything Updated
90% of hacked sites were running outdated software. Enable automatic updates.
// wp-config.php - Force automatic updates
define('WP_AUTO_UPDATE_CORE', true);
add_filter('auto_update_plugin', '__return_true');
add_filter('auto_update_theme', '__return_true');
Enable auto
Enable auto
Enable auto
Use Strong Passwords & Password Manager
Weak passwords cause 30% of breaches. Use 16+ characters with special chars.
❌ admin2026
✅ G%8nB^3vF*6tY~4w
Recommended: 1Password, Bitwarden, LastPass
Remove Default Admin User
Never use 'admin' as username. Create new admin and delete default.
-- SQL to check for admin user SELECT * FROM wp_users WHERE user_login = 'admin'; -- Create new admin via WP-CLI wp user create newadmin email@domain.com --role=administrator wp user delete 1 --reassign=newadmin
Change Database Table Prefix
Default 'wp_' makes SQL injection easier. Change during install or with plugin.
// wp-config.php - Change prefix $table_prefix = 'wp_6a9k2m_'; // Random 8 chars + underscore
⚠️ Only change during fresh install or with backup
Disable File Editing in Dashboard
Prevent hackers from editing theme/plugin files via admin.
// wp-config.php
define('DISALLOW_FILE_EDIT', true);
⚙️ PHP 8.3 Advanced Security Features (Tips 6-10)
Enable PHP 8.3's Random Extension
Use cryptographically secure random number generator for tokens and passwords.
// PHP 8.3 secure random generator
$token = bin2hex(random_bytes(32)); // 64 char secure token
// For passwords - use native functions
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
if (password_verify($password, $hash)) {
// Authenticated
}
Configure php.ini Security Settings
; Critical PHP security settings disable_functions = exec,shell_exec,system,passthru,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source allow_url_fopen = Off allow_url_include = Off expose_php = Off display_errors = Off log_errors = On error_log = /path/to/php-errors.log session.cookie_httponly = 1 session.cookie_secure = 1 session.use_strict_mode = 1 session.use_only_cookies = 1
Implement Content Security Policy Headers
# .htaccess - CSP Headers Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'self'; form-action 'self';"
Enable XSS Protection Headers
# Security Headers Header set X-XSS-Protection "1; mode=block" Header set X-Content-Type-Options "nosniff" Header set X-Frame-Options "SAMEORIGIN" Header set Referrer-Policy "strict-origin-when-cross-origin" Header set Permissions-Policy "geolocation=(), microphone=(), camera=()"
Use Sodium for Encryption
// PHP 8.3 Sodium encryption // Encrypt sensitive data $key = sodium_crypto_secretbox_keygen(); $nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); $encrypted = sodium_crypto_secretbox($data, $nonce, $key); // Decrypt $decrypted = sodium_crypto_secretbox_open($encrypted, $nonce, $key);
🔐 Authentication & Login Security (Tips 11-15)
Enable Two-Factor Authentication (2FA)
2FA blocks 99.9% of automated attacks.
Free
Free
Plugin
Limit Login Attempts
// functions.php - Custom login limiting
function check_login_attempts($username) {
$ip = $_SERVER['REMOTE_ADDR'];
$attempts = get_transient('login_attempts_' . $ip);
if ($attempts && $attempts >= 5) {
return new WP_Error('too_many_attempts', 'Too many login attempts. Try again in 15 minutes.');
}
set_transient('login_attempts_' . $ip, $attempts + 1, 900);
return $username;
}
add_filter('authenticate', 'check_login_attempts', 30, 2);
Change Login URL
Hide wp-admin from bots and automated attacks.
// functions.php - Change login URL
function custom_login_url() {
return home_url('/secure-access');
}
add_filter('login_url', 'custom_login_url');
// Also in .htaccess
RewriteRule ^wp-admin$ - [F]
RewriteRule ^wp-login\.php$ - [F]
Use reCAPTCHA on Login
<!-- Add to login form -->
<script src="https://www.google.com/recaptcha/api.js"></script>
<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY"></div>
<?php
// Verify on login
$recaptcha = $_POST['g-recaptcha-response'];
$response = file_get_contents("https://www.google.com/recaptcha/api/siteverify?secret=YOUR_SECRET&response={$recaptcha}");
if (!$response['success']) {
wp_die('reCAPTCHA verification failed');
}
?>
Force Strong Passwords for All Users
// functions.php - Password strength enforcement
function enforce_strong_password($errors, $update, $user) {
$password = $_POST['pass1'] ?? '';
if (strlen($password) < 12) {
$errors->add('weak_password', 'Password must be at least 12 characters');
}
if (!preg_match('/[!@#$%^&*]/', $password)) {
$errors->add('weak_password', 'Password must contain special character');
}
return $errors;
}
add_filter('user_profile_update_errors', 'enforce_strong_password', 10, 3);
📁 File Permissions & Ownership (Tips 16-20)
Set Correct File Permissions
# Standard WordPress permissions
find /path/to/wordpress -type d -exec chmod 755 {} \;
find /path/to/wordpress -type f -exec chmod 644 {} \;
# Special directories need 775 for uploads
chmod 775 wp-content/uploads
chmod 775 wp-content/cache
# Critical files should be 600
chmod 600 wp-config.php
chmod 600 .htaccess
Secure wp-config.php Location
Move wp-config.php one level above public_html.
# Directory structure
/home/user/
├── wp-config.php # Moved up one level
└── public_html/ # WordPress core
├── wp-admin/
├── wp-content/
└── wp-includes/
Protect Sensitive Files with .htaccess
# Block access to sensitive files
<FilesMatch "^(wp-config\.php|install\.php|php\.ini|\.htaccess)">
Order Allow,Deny
Deny from all
</FilesMatch>
# Disable directory browsing
Options -Indexes
# Protect includes directory
<IfModule mod_rewrite.c>
RewriteRule ^wp-admin/includes/ - [F]
RewriteRule ^wp-includes/[^/]+\.php$ - [F]
</IfModule>
Disable PHP Execution in Uploads
# In wp-content/uploads/.htaccess
<Files *.php>
deny from all
</Files>
# Or more thorough
<IfModule mod_php7.c>
php_flag engine off
</IfModule>
Regular File Integrity Scanning
#!/bin/bash
# Weekly file integrity check
cd /path/to/wordpress
find . -type f -name '*.php' -mtime -7 -exec ls -la {} \; > changed_files.txt
# Check against WordPress core checksums
wp core verify-checksums > core_verification.txt
# Monitor for suspicious files
find . -name '*.php' -exec grep -l "eval(" {} \; > suspicious.txt
find . -name '*.php' -exec grep -l "base64_decode" {} \; >> suspicious.txt
🛡️ Firewall & Web Application Firewall (Tips 21-25)
Use Cloudflare WAF
Cloudflare's free WAF blocks SQL injection, XSS, and DDoS attacks.
- Under Security → WAF
- Turn on "Managed Ruleset"
- Set to "High" sensitivity
- Block country access
- Rate limiting
- Bot fight mode
Install Wordfence Security Plugin
Most comprehensive WordPress firewall (free version available).
# Wordfence CLI scan wordfence scan --malware --core --plugins --themes # Real-time firewall rules # Blocks malicious IPs, SQL injection, XSS
Create Custom .htaccess Firewall Rules
# Block malicious requests
RewriteCond %{QUERY_STRING} (eval\() [NC,OR]
RewriteCond %{QUERY_STRING} (base64_encode|base64_decode) [NC,OR]
RewriteCond %{QUERY_STRING} (union.*select.*\() [NC,OR]
RewriteCond %{QUERY_STRING} (concat.*\() [NC]
RewriteRule .* - [F]
# Block bad bots
RewriteCond %{HTTP_USER_AGENT} (ahrefs|semrush|majestic|archive) [NC]
RewriteRule .* - [F]
# Block certain HTTP methods
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK|DELETE) [NC]
RewriteRule .* - [F]
Implement IP Blacklisting/Whitelisting
# Allow only specific IPs to wp-admin
<Files wp-login.php>
Order Deny,Allow
Deny from all
Allow from 192.168.1.100 # Your IP
Allow from 10.0.0.0/24 # Office network
</Files>
# Block known bad IPs
deny from 123.45.67.89
deny from 98.76.54.32
Enable Rate Limiting
# Nginx rate limiting
http {
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
server {
location /wp-login.php {
limit_req zone=login burst=1 nodelay;
}
}
}
# Cloudflare rate limiting
# Security → WAF → Rate Limiting Rules
# Rule: 5 requests per minute to /wp-login.php
🗄️ Database Security Hardening (Tips 26-30)
Create Separate Database User
Never use root. Create limited user for WordPress only.
-- Create limited database user CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'StrongPassword123!'; GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX ON wordpress.* TO 'wpuser'@'localhost'; FLUSH PRIVILEGES;
Change Database Password Regularly
#!/bin/bash
# Monthly password rotation
NEW_PASS=$(openssl rand -base64 32)
mysql -e "ALTER USER 'wpuser'@'localhost' IDENTIFIED BY '$NEW_PASS';"
sed -i "s/define('DB_PASSWORD', '.*')/define('DB_PASSWORD', '$NEW_PASS')/" wp-config.php
Use Encrypted Database Connections
// wp-config.php - Force SSL for DB
define('MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL);
# MySQL config - require SSL
[mysqld]
require_secure_transport = ON
ssl-ca = /path/to/ca.pem
ssl-cert = /path/to/server-cert.pem
ssl-key = /path/to/server-key.pem
Regular Database Backups
#!/bin/bash
# Daily encrypted backup
BACKUP_FILE="wp_backup_$(date +%Y%m%d).sql"
mysqldump -u wpuser -p wordpress > $BACKUP_FILE
# Encrypt backup
gpg --symmetric --cipher-algo AES256 $BACKUP_FILE
# Upload to secure storage
rclone copy ${BACKUP_FILE}.gpg remote:backups/
# Keep only last 30 days
find . -name "*.sql" -mtime +30 -delete
Remove Unused Database Tables
-- Find and drop unused plugin tables SELECT table_name FROM information_schema.tables WHERE table_schema = 'wordpress' AND table_name LIKE '%_spam_%'; DROP TABLE wp_bad_plugin_table;
🔌 Plugin Security Best Practices (Tips 31-35)
Only Install from Trusted Sources
- ✅ WordPress.org repository
- ✅ Reputable developers (Yoast, WooCommerce, etc.)
- ❌ Nulled/cracked plugins
- ❌ Random GitHub repos
- ❌ Torrent sites
Delete Unused Plugins
Inactive plugins can still be security risks.
# List all plugins wp plugin list # Delete inactive plugins wp plugin delete $(wp plugin list --status=inactive --field=name) # Or via SQL DELETE FROM wp_options WHERE option_name LIKE '%plugin_name%';
Check Plugin Vulnerabilities
#!/bin/bash
# Check against WPScan vulnerability database
wpscan --url https://yoursite.com --api-token YOUR_TOKEN
# Or use CLI
wp plugin list --format=csv | while IFS=, read name status version
do
curl "https://wpscan.com/api/v3/plugins/$name" -H "Authorization: Token token=YOUR_TOKEN"
done
Limit Plugin Capabilities
// functions.php - Restrict plugin access
function restrict_plugin_access() {
if (!current_user_can('manage_options')) {
deactivate_plugins(array('plugin-folder/plugin-file.php'));
}
}
add_action('admin_init', 'restrict_plugin_access');
// Remove plugin menu for non-admins
if (!current_user_can('administrator')) {
remove_menu_page('plugins.php');
}
Audit Plugin Code for Malware
#!/bin/bash
# Scan for suspicious patterns
grep -r "eval(" wp-content/plugins/
grep -r "base64_decode" wp-content/plugins/
grep -r "system(" wp-content/plugins/
grep -r "curl_" wp-content/plugins/
grep -r "preg_replace.*\/e" wp-content/plugins/
# Check for encrypted code
find wp-content/plugins/ -name "*.php" -exec grep -l "eval(gzinflate" {} \;
find wp-content/plugins/ -name "*.php" -exec grep -l "str_rot13" {} \;
🔒 SSL & HTTPS Configuration (Tips 36-40)
Install SSL Certificate
Use Let's Encrypt for free, auto-renewing certificates.
# Install Certbot sudo apt install certbot python3-certbot-apache # Get certificate sudo certbot --apache -d yourdomain.com -d www.yourdomain.com # Auto-renewal sudo certbot renew --dry-run
Force HTTPS Everywhere
// wp-config.php
define('FORCE_SSL_ADMIN', true);
# .htaccess - Force HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
# Nginx
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
Use Strong SSL Configuration
# Nginx SSL configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_stapling on; ssl_stapling_verify on;
Fix Mixed Content Warnings
// functions.php - Fix mixed content
function fix_mixed_content($content) {
return str_replace('http://', 'https://', $content);
}
add_filter('the_content', 'fix_mixed_content');
add_filter('post_thumbnail_html', 'fix_mixed_content');
add_filter('wp_get_attachment_url', 'fix_mixed_content');
// Or use plugin: Really Simple SSL
Enable HSTS (HTTP Strict Transport Security)
# .htaccess Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS # Nginx add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; # Submit to HSTS preload list # https://hstspreload.org/
💾 Backup Security & Disaster Recovery (Tips 41-45)
Follow 3-2-1 Backup Rule
- 3 copies of your data
- 2 different storage types
- 1 off-site backup
Encrypt Backups
#!/bin/bash # Create encrypted backup tar -czf wordpress.tar.gz /var/www/html gpg --symmetric --cipher-algo AES256 wordpress.tar.gz rm wordpress.tar.gz # Store key separately gpg --export-secret-keys > backup-key.asc # Decrypt when needed gpg --output wordpress.tar.gz --decrypt wordpress.tar.gz.gpg tar -xzf wordpress.tar.gz
Test Backups Monthly
#!/bin/bash # Automated restore testing cd /tmp gpg --decrypt latest-backup.tar.gz.gpg > backup.tar.gz tar -xzf backup.tar.gz docker run --rm -v $(pwd):/var/www/html wordpress:6.9 php /var/www/html/wp-admin/install.php echo $? # Check exit code
Secure Backup Storage
# AWS S3 with encryption
aws s3 cp backup.tar.gz.gzip s3://your-bucket/ --sse AES256
# With lifecycle policy
aws s3api put-bucket-lifecycle-configuration \
--bucket your-bucket \
--lifecycle-configuration file://lifecycle.json
# lifecycle.json
{
"Rules": [{
"Id": "Delete old backups",
"Status": "Enabled",
"Prefix": "",
"Expiration": { "Days": 90 }
}]
}
Create Disaster Recovery Plan
- Detect hack (monitoring alerts)
- Isolate site (maintenance mode)
- Restore from clean backup
- Change all passwords
- Scan for malware
- Update everything
- Investigate breach cause
- Reinforce security
- Bring site back online
- Document incident
📊 Security Monitoring & Audit Logs (Tips 46-50+)
Implement Audit Logging
// Custom audit log
function log_security_event($action, $details = []) {
global $wpdb;
$log = [
'user_id' => get_current_user_id(),
'action' => $action,
'details' => json_encode($details),
'ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT'],
'timestamp' => current_time('mysql')
];
$wpdb->insert($wpdb->prefix . 'security_audit', $log);
}
// Track logins
add_action('wp_login', function($user_login, $user) {
log_security_event('login_success', ['user' => $user_login]);
}, 10, 2);
add_action('wp_login_failed', function($username) {
log_security_event('login_failed', ['username' => $username]);
});
Set Up File Integrity Monitoring
#!/bin/bash # AIDE - Advanced Intrusion Detection Environment apt install aide aideinit mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db # Daily check aide --check | mail -s "AIDE Report" admin@domain.com # Tripwire alternative tripwire --check tripwire --update --twfile /etc/tripwire/tw.pol
Configure Real-Time Alerts
// Slack alerts for critical events
function send_slack_alert($message) {
$webhook = 'https://hooks.slack.com/services/YOUR/WEBHOOK';
$data = json_encode(['text' => $message]);
wp_remote_post($webhook, [
'headers' => ['Content-Type' => 'application/json'],
'body' => $data
]);
}
// Alert on admin creation
add_action('user_register', function($user_id) {
if (user_can($user_id, 'administrator')) {
send_slack_alert("🚨 New admin created: User ID $user_id");
}
});
Monitor Failed Login Attempts
#!/bin/bash
# Analyze auth logs
grep "Failed password" /var/log/auth.log | awk '{print $1,$2,$3,$11}' | sort | uniq -c | sort -nr
# Fail2ban configuration
apt install fail2ban
cat > /etc/fail2ban/jail.local << EOF
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
EOF
Regular Security Audits
#!/bin/bash # Monthly security audit script echo "=== WordPress Security Audit ===" date echo -e "\n1. Checking WordPress version" wp core version echo -e "\n2. Verifying core files" wp core verify-checksums echo -e "\n3. Checking plugin vulnerabilities" wpscan --url https://yoursite.com --api-token YOUR_TOKEN echo -e "\n4. Scanning for malware" clamscan -r /var/www/html/ echo -e "\n5. Checking file permissions" find /var/www/html -type f -perm 777 -ls echo -e "\n6. Reviewing user accounts" wp user list echo -e "\n7. Checking SSL expiration" echo | openssl s_client -servername yoursite.com -connect yoursite.com:443 2>/dev/null | openssl x509 -noout -dates echo -e "\n8. Testing backups" ls -lh /backups/latest/ echo -e "\n=== Audit Complete ==="
Bonus: 5 Advanced Security Tips
- 51. Use Web Application Firewall (Cloudflare, Sucuri)
- 52. Implement Security Headers scanner (securityheaders.com)
- 53. Disable XML-RPC (add to .htaccess:
RewriteRule ^xmlrpc.php - [F]) - 54. Use Security Keys Salts generator (api.wordpress.org/secret-key/1.1/salt/)
- 55. Regular penetration testing with tools like WPScan
✅ Security Checklist (Printable)
- WordPress core updated
- All plugins updated
- All themes updated
- Strong passwords enforced
- 2FA enabled for all admins
- Login attempt limiting
- Default admin user removed
- File permissions correct
- wp-config.php secured
- SSL/HTTPS enforced
- Firewall enabled
- Daily backups configured
- Audit logging active
- Security monitoring set up
⭐ Download PDF checklist: Security Checklist 2026
❓ Security FAQ
What's the most important security step?
Keeping everything updated. 90% of hacked sites were running outdated software.
Which security plugin is best?
Wordfence offers the most complete protection. Solid Security is great for hardening.
How often should I backup?
Daily for active sites, weekly for static sites. Store backups off-site encrypted.
What do I do if hacked?
1. Take site down 2. Restore from clean backup 3. Change all passwords 4. Find vulnerability
📬 Get Weekly Security Alerts & Tips
Stay ahead of hackers with latest vulnerabilities and fixes.
📢 Share this security guide to protect others