Most WordPress compromises stay hidden for weeks. No defaced homepage, no ransom note.

More on how to spot a compromised WordPress site

Technical support for suspected WordPress hacks

Any malicious infection leaves traces. Here's how to find them systematically using the command line.

Core file integrity checks

Start by verifying your WordPress core hasn't been tampered with. Download a fresh copy and compare:

# Download fresh WordPress
cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz

# Compare against your site (adjust path as needed)
diff -rq wordpress/ /var/www/html/ --exclude=wp-config.php --exclude=wp-content

Any differences outside wp-config.php and wp-content/ warrant investigation. Core files only change on updates.

File modification hunting

List files modified recently; legitimate updates will be obvious:

# Files changed in the last 7 days
find /var/www/html -type f -mtime -7 -ls

# Specifically look for PHP in uploads (should never happen)
find /var/www/html/wp-content/uploads -name "*.php" -ls

# Find recently modified core files (these are the danger zone)
find /var/www/html/wp-includes /var/www/html/wp-admin -type f -mtime -30

Database scanning for injected content

Malware hides in database content too, not just files. Connect and search:

-- Look for suspicious script tags in posts
SELECT ID, post_title FROM wp_posts 
WHERE post_content LIKE '%<script%' 
OR post_content LIKE '%base64_decode%'
OR post_content LIKE '%eval(%';

-- Check for unfamiliar admin users
SELECT ID, user_login, user_email, display_name 
FROM wp_users 
WHERE ID > 2 OR user_login NOT IN ('your-username');

-- Inspect wp_options for suspicious cron entries
SELECT option_value FROM wp_options 
WHERE option_name = 'cron';

From the shell you can dump this:

mysqldump -u dbuser -p dbname | grep -i 'base64\|eval\|<script'

Process and resource monitoring

Crypto miners and command-and-control clients consume resources. Check active processes:

# Look for suspicious processes
ps auxf | grep -E 'miner|cryptonight|xmrig|node.*evil'

# Check network connections from your web user
netstat -tunlp | grep www-data
ss -tunlp | grep :80

# Monitor real-time resource usage
watch -n 5 'top -b -c | head -20'

If your hosting provider is nagging you about CPU spikes but you've made no changes, this is worth investigating.

Cron and scheduled task inspection

Attackers persist through malicious cron jobs. Check both system and WordPress scheduler:

# System crontab
crontab -l -u www-data

# WordPress database cron (decode the serialized data)
mysql -u dbuser -p dbname -e "SELECT option_value FROM wp_options WHERE option_name='cron'" | php -r "print_r(unserialize(stream_get_contents(STDIN)));"

# Look for suspicious entries in /etc/cron.d/
grep -r wordpress /etc/cron.d/

XML-RPC abuse detection

XML-RPC is still abused for brute force attacks. Check your access logs:

# Count XML-RPC hits in last 24 hours
grep xmlrpc.php /var/log/apache2/access.log* | wc -l

# See which IPs are hammering it
grep xmlrpc.php /var/log/apache2/access.log* | awk '{print $1}' | sort | uniq -c | sort -rn | head -10

# Block it if you don't need it (add to .htaccess)
# <Files xmlrpc.php>
#   Order Deny,Allow
#   Deny from All
# </Files>

For Apache running on Lightsail, verify the module is loaded first:

apachectl -M | grep headers

If mod_headers isn't there, Header set directives will throw 500 errors.

Version leakage audit

Attackers fingerprint your setup before exploiting it. Search for exposed versions:

# Check page headers
curl -I https://yourdomain.com | grep -i 'wordpress\|generator'

# Scan feeds for version strings
curl https://yourdomain.com/feed | grep -i 'generator'

# Check for readme.html (classic giveaway)
curl -I https://yourdomain.com/readme.html

If these leak versions, add removal code to your theme's functions.php or use a security plugin.

External reconnaissance

Sometimes the compromise shows up externally before you find it internally:

# Check blacklisting status via curl to public APIs
curl -s "https://www.google.com/safebrowsing/?hl=en&url=https://yourdomain.com" | grep -i blocked

# Run external scans
curl "https://sitecheck.sucuri.net/api/scanner?url=yourdomain.com"

These won't catch server-side malware but will surface blacklisting and cloaking that affects visitors.

Finding hidden PHP files

Look for files that don't belong, including those with odd permissions:

# Files with execute permissions in uploads
find /var/www/html/wp-content/uploads -perm /111 -type f -ls

# Files created without FTP activity (compare against known-good list)
find /var/www/html -name "*.php" -type f -exec ls -la {} \; | grep -v 'your-ftp-username'

# Search for obfuscated function names
grep -r 'eval(\$_REQUEST' /var/www/html --include="*.php"
grep -r 'base64_decode(str_rot' /var/www/html --include="*.php"

Access log forensic analysis

Dig into your access patterns for anomalies:

# Find unusual 404 attempts (probing for vulnerable plugins)
grep '" 404 ' /var/log/apache2/access.log | awk '{print $7, $8}' | sort | uniq -c | sort -rn | head -20

# Spot POST requests to files that shouldn't accept them
grep 'POST' /var/log/apache2/access.log | grep -v 'wp-login.php\|xmlrpc.php'

# Identify high-frequency IPs (brute force or scraping)
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

Immediate remediation steps

When you find something, act fast but document everything:

# Backup the compromised state first
rsync -avz /var/www/html/ /backup/compromised-$(date +%Y%m%d)/
mysqldump -u dbuser -p dbname > /backup/db-compromised-$(date +%Y%m%d).sql

# Change all credentials
# 1. MySQL passwords (update wp-config.php)
# 2. Admin passwords (reset via wp-cli)
wp user update administrator --user_pass='newstrongpassword' --porcelain
# 3. Database user password
mysql -e "ALTER USER 'dbuser'@'localhost' IDENTIFIED BY 'newpassword';"

# Remove malicious users
wp user delete baduser --reassign=administrator

Prevention checklist

Fix the entry point or you'll repeat this. Most infections come from:

  • Outdated plugins; run wp plugin list --status=inactive and delete what you don't use
  • Nulled or pirated themes; they're malware carriers
  • Weak admin passwords; enforce strong authentication via security plugins
  • Missing file permissions hardening; your uploads folder should not be writable by Apache

A few key .htaccess rules worth implementing:

# Block direct PHP execution in uploads
<FilesMatch "\.(php|php7|phtml)$">
    Order Allow,Deny
    Deny from all
</FilesMatch>

# Disable directory listing
Options -Indexes

# Protect wp-config.php
<files wp-config.php>
    Order Allow,Deny
    Deny from all
</files>

Test these carefully; misconfiguration takes sites down with 500 errors.

More on how to spot a compromised WordPress site