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

Often here's no dramatic defacement, no ransom note, no angry emails from customers. Instead, the compromise sits quietly in the background, harvesting credit card details, sending spam, or quietly redirecting your visitors somewhere you really don't want them to go. By the time most site owners notice, the malware has been there for weeks or months.

The good news is that compromises leave fingerprints. If you know where to look, you can catch an infection early, before it trashes your search rankings or gets your domain blacklisted. Here's what I look for when auditing a WordPress site, plus the quick checks you can run yourself today.

The warning signs

1. Unexplained traffic drops or ranking changes

A sudden dip in organic traffic is often the first visible symptom. Malicious scripts injected into your pages can trip Google's Safe Browsing warnings, trigger "this site may be hacked" notices in search results, or cloak content so that search engines see something different from your visitors. Check Google Search Console for security issues and manual actions; it's free and it tells you what Google actually sees.

2. Strange files in your installation

Attackers love to drop files with innocent-looking names into directories nobody watches. Classic hiding spots include:

  • wp-content/uploads/, which should only ever contain media files, never PHP
  • Your theme's root directory and child directories
  • wp-includes/ and wp-admin/, where files masquerading as wp-class.php or wp-tmp.php sit alongside genuine core files

A file modified recently in wp-includes/ almost always means trouble. Legitimate core files only change when you update WordPress.

3. Suspicious cron jobs and scheduled tasks

Few things are as overlooked as WordPress's own scheduler. Compromised sites often gain malicious entries in the wp_options table under cron, silently re-downloading malware even after you've cleaned the files. While you're there, check for phantom admin users. Attackers frequently create accounts with usernames like wp_support or admin_2024 and give them administrator rights.

4. Injected scripts and iframes

Base64-encoded strings, long minified blobs appended to your functions.php, or <script> tags referencing unfamiliar external domains are all red flags. Cloaking scripts are particularly sneaky: they check whether the visitor came from Google or is using a mobile device, then show the malware only to those users. That's why the site owner often browses their own site and sees nothing wrong, while customers are being hit.

5. Your site is slower than it should be

Malware isn't written for performance. Crypto-mining scripts, spam-generation routines, and outbound connections to command-and-control servers all eat resources. If your hosting provider suddenly starts nagging you about CPU limits, and nothing on the site has changed, investigate.

6. Search results you didn't write

Query Google with site:yourdomain.com and look for Japanese pharmaceutical spam, poker pages, or anything in a language you don't recognise. The "Japanese keyword hack" is notorious for injecting thousands of gibberish pages that only appear in search results, invisible when browsing the site normally.

Quick checks you can run today

Diff your core files. Download a fresh copy of WordPress from wordpress.org and compare it against your installation. Any difference outside wp-config.php and wp-content/ deserves scrutiny.

Check file modification times. From SSH, find . -mtime -3 -type f lists everything changed in the last three days. Legitimate updates are obvious; unexpected changes are not.

Inspect the database. Look at the wp_users table for unfamiliar accounts, and search your posts and pages for <script> and base64_decode.

Scan your site externally. Tools like Sucuri's SiteCheck and UpGuard surface injected content, blacklisting status and exposed version information. Nothing beats a proper server-side scan, but external checks are fast and catch a lot.

Review your access logs. Look for POST requests to files that shouldn't accept POST requests, or repeated hits to xmlrpc.php. Which brings us to the biggest single win most WordPress sites can make.

Close the door behind you

Spotting an infection is only half the battle. The same audit should cover your exposure:

  • Disable XML-RPC entirely unless you have a specific dependency on it; it's a brute-force magnet and most sites never use it
  • Remove version leakage from your page head, feeds and readme files so attackers can't trivially match your site against known plugin vulnerabilities
  • Keep plugins updated religiously, and delete the ones you've stopped using; abandoned plugins are the number one infection vector I see
  • Set security headers properly, but test them carefully; a misconfigured Header set directive in .htaccess can take a whole site down with a 500 error
  • Back up regularly, store backups off-site, and actually test restoring one

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.


Ten minutes of systematic checks weekly catches most compromises before they cascade. Set a reminder, run the file diffs, review new users, glance at Search Console. Automation helps but nothing replaces periodic hands-on inspection.

If you're managing multiple WordPress installations or simply don't want to think about this at all, I can audit your sites and harden the configuration. Get in touch and we'll sort it.