How to Clean a Hacked WordPress Site (Step-by-Step)
Your WordPress site has been hacked. How to identify the malware, remove it completely, close the entry point, and verify clean operation.
A hacked WordPress site is stressful but recoverable. The key is acting methodically: identify the infection, remove it completely, close the entry point, and verify the cleanup. Skipping steps - especially identifying the entry point - means the malware comes back within days.
This guide covers the full process from initial detection through verified clean operation.
Step 1 - Confirm the site is actually hacked
Symptoms vary by attack type. Common signs:
- Google Search Console warning: "This site may be hacked" or blacklisting notification
- Browser security warnings (Google Safe Browsing, Chrome phishing warning)
- Visitors being redirected to spam or pharma sites
- Google index shows strange pages you did not create (
/viagra-cheap-buy/, casino sites, etc.) - Admin account locked out or unknown admin accounts present
- Hosting provider suspended the account for malware
- Site visitors report seeing pop-ups or strange content
- Site loads a blank page or white screen of death that appeared suddenly
Run the site through external scanners to get an outside view:
- Sucuri SiteCheck (
sitecheck.sucuri.net) - checks blacklist status and visible malware - Google Safe Browsing (
transparencyreport.google.com/safe-browsing/search) - check if Google has flagged the domain - VirusTotal - check the domain against 70+ security vendors
These scanners only see what an external visitor sees. They will miss malware that only runs for logged-in users, malware hidden in database records, or backdoors that are not actively serving malicious content.
Step 2 - Take the site offline
Put the site in maintenance mode immediately. Leaving an infected site running:
- Continues serving malware to visitors
- Continues running the attacker's code (which may be mining cryptocurrency, sending spam, or attacking other sites)
- Gives you a moving target for cleanup
If you have server access:
# Simple maintenance page via Nginx
location / {
return 503;
}
error_page 503 /maintenance.html;
Or rename the site's document root temporarily and replace with a static HTML page.
Step 3 - Secure a backup before touching anything
Before you delete a single file, take a full backup of the compromised site. Even an infected backup is valuable:
- It preserves your database, content, and media files
- It lets you diff files later to find exactly what changed
- It is your only option if cleanup damages the database
# Database backup wp db export backup-infected-$(date +%Y%m%d).sql # Files backup tar czf backup-infected-$(date +%Y%m%d).tar.gz /var/www/html
Store these somewhere safe and clearly labelled as infected.
Step 4 - Identify the malware and entry point
Find modified files
Look for files changed recently (adjust the time window to when symptoms appeared):
# Files modified in the last 7 days find /var/www/html -type f -newer /var/www/html/wp-config.php -name "*.php" # PHP files modified in the last 30 days find /var/www/html -name "*.php" -mtime -30 -ls | sort -k8
Look for common malware patterns
# Encoded/obfuscated PHP
grep -r --include="*.php" "base64_decode" /var/www/html
grep -r --include="*.php" "eval(" /var/www/html
grep -r --include="*.php" "gzinflate\|str_rot13\|gzuncompress" /var/www/html
# PHP in uploads (should never be there)
find /var/www/html/wp-content/uploads -name "*.php"
# Malicious iframe injections
grep -r "iframe" /var/www/html/wp-content/themes --include="*.php"
Many of these patterns appear in legitimate plugins too (serialized data, compressed scripts). Context matters - look at the full file, not just the matched line.
Check the database for injected content
wp db search "base64_decode" --all-tables
wp db search "<script" --all-tables
wp db search "eval(" --all-tables
Injected JavaScript in post content, widget content, or options is common. Attackers often inject into the wp_options table (siteurl, home, or custom options they add).
Check for backdoors
A backdoor lets the attacker re-enter after cleanup. Common locations:
wp-content/uploads/- PHP files disguised as imageswp-content/plugins/- extra PHP files added to legitimate plugins- Theme files - extra functions in
functions.php wp-content/mu-plugins/- must-use plugins that load automatically
# PHP files in uploads (all should be treated as suspicious) find /var/www/html/wp-content/uploads -name "*.php" -o -name "*.phtml" # Filenames that look like WordPress core but are not find /var/www/html -name "wp-*.php" | grep -v "wp-content\|wp-admin\|wp-includes"
Step 5 - Clean WordPress core files
Download a fresh copy of WordPress matching your current version:
wp core download --force --version=$(wp core version)
The --force flag overwrites all core files. This replaces any modified core files with clean originals. It does not touch wp-content/ or wp-config.php.
Verify the checksums:
wp core verify-checksums
Any files that fail checksum verification were modified. If wp-settings.php or wp-load.php is modified, that is a strong indicator of a serious compromise.
Step 6 - Clean plugins and themes
The safest approach: delete all plugins and themes, then reinstall from official sources.
# Remove all plugins rm -rf /var/www/html/wp-content/plugins/* # Reinstall from WordPress.org wp plugin install [plugin-slug] --activate # For premium plugins - reinstall from vendor
For premium plugins you cannot reinstall via WP-CLI, download fresh copies from the vendor and upload via SFTP.
Do not restore plugins from your infected backup. The backup may contain the original malware.
For themes: delete all themes except the one in active use, then reinstall the active theme from scratch. If it is a custom theme, you need to carefully review each file.
Step 7 - Clean the database
Database cleanup is the most sensitive step - mistakes can lose content.
Remove injected content from posts:
# Find posts with injected script tags
wp post list --field=ID | xargs -I {} wp post get {} --field=post_content | grep -n "<script"
For widespread injection, use a plugin like Better Search Replace to find and replace malicious strings across all database tables. Run it in dry-run mode first.
Check and clean wp_options:
# List all options - look for unfamiliar ones wp option list # Check siteurl and home are correct wp option get siteurl wp option get home # Remove malicious options wp option delete [suspicious-option-name]
Remove unknown admin accounts:
wp user list --role=administrator
Delete any accounts you did not create.
Step 8 - Change all credentials
After cleanup, assume all credentials are compromised:
- WordPress admin passwords - reset all admin accounts
- Database password - change in MySQL and update
wp-config.php - WordPress auth keys and salts - regenerate (logs out all sessions)
- Hosting control panel password
- FTP/SFTP credentials - disable FTP entirely if possible; use SFTP only
- SSH keys - if you suspect SSH compromise, regenerate keys and remove unauthorised ones from
~/.ssh/authorized_keys
Step 9 - Identify and close the entry point
Cleanup without closing the entry point means the same attacker (or the same automated bot) re-infects within hours.
Check your server access logs for the time period before symptoms appeared:
# Nginx grep "POST" /var/log/nginx/access.log | grep "2025-01-20\|2025-01-21" # Look for suspicious POSTs to PHP files in unusual locations grep "uploads.*\.php" /var/log/nginx/access.log
Common entry points:
- Vulnerable plugin or theme - check WPScan database for CVEs matching your installed versions
- Compromised admin account - check for logins from unexpected IPs
- Weak FTP/SFTP password - check FTP access logs
- Compromised hosting account - contact your host if other sites on the account are also infected
Once identified, update the vulnerable plugin/theme, or block the specific exploit with a WAF rule.
Step 10 - Verify and monitor
After cleanup:
- Run
wp core verify-checksums- all should pass - Run a Wordfence or Sucuri scan
- Re-check Google Safe Browsing status (can take 1-3 days to clear after cleanup)
- If Google blacklisted the site, request a review through Search Console
- Set up file change monitoring so you are alerted immediately if files change again
Monitor access logs daily for the first week post-cleanup. A returning attacker often tries the same entry point again.
When to call a professional
If the infection is widespread (hundreds of modified files, heavily obfuscated malware, database-level injection across all content), professional cleanup is faster and more reliable than manual cleaning. Sucuri and Wordfence both offer guaranteed malware removal services. The cost of professional cleanup is almost always less than the revenue lost from extended downtime or continued spam penalties.
Related reading
// new_articles
Get notified when new guides drop
Practical WordPress guides from a working agency owner. No filler. Unsubscribe any time.
Was this article helpful?
Thanks for the feedback!