The Reinfector That Isn't in Your Files: How a WordPress Infection Survives a Perfect Cleanup
You did it the right way this time. You found every infected file, you removed them all in one go instead of one by one, and you cleared the database entries too. The site looked clean. Less than a minute later, the fake plugin was back in exactly the same place.
That isn't a sign you missed a file. It's a sign that the thing rebuilding your site was never a file to begin with. A growing class of WordPress infections keeps its engine somewhere a file scan cannot reach: inside programs that are still running on the server, in the server's memory, or in a scheduled task that your security plugin never sees.
This article walks through how one well-documented malware family does it in its newer versions, which signs point to an engine living outside your files, and what to ask your host to check. You don't need to read any PHP to follow along.
How the attack works
We've written before about self-healing malware: infections that plant several copies of themselves, each able to rebuild the others, so deleting them one at a time never ends. The standard answer to that is to take a full inventory first and remove everything at once.
The newer versions of the same family were built to survive that answer. They still keep plenty of copies on disk, but they also keep a copy of the payload alive in places that have nothing to do with the files in your site folder. When you delete the files, the running copy notices and writes them back. When you clear the database, it writes that back too.
So the cleanup has two halves. The files and database are the half you can see. The other half is whatever is currently executing, and until that stops, every perfect file cleanup is temporary.
Technical analysis: where the engine hides
1. A map of its own restore points
The infection keeps a list of every place it has stored a copy of itself, written into the WordPress database as a setting. That list is what lets it rebuild in seconds: it doesn't have to search, it just walks the list.
The restore points are deliberately scattered. Copies of the payload sit inside zip files named with eight random hexadecimal characters, placed in up to three locations at once: the wp-content folder, a theme folder, and a dated folder under uploads. A hidden folder under wp-content whose name starts with .sc_ holds the core of the kit, a file of roughly 540 KB, along with lock files and a heartbeat file rewritten every minute. A fake object-cache.php of just 56 bytes loads the payload from a data file next to it. There's a backup copy of your theme's functions.php, a line added to wp-config.php, and dozens of database settings, about 55 per site in one case, some of them disguised as harmless temporary cache entries.
Miss any one of these and the infection has a seed to regrow from.
2. A process that keeps running after its file is deleted
On several servers, the kit launched a background PHP program, separate from any web request, identified by a --sc-cli flag in the process list. It runs as your hosting account's user, holds the payload in memory, and checks every minute that its pieces are still in place.
The detail that makes this so confusing is that the program keeps running even after its own file is gone. On one server, the process was still alive and active while the file it had started from no longer existed on disk; the hidden folder held a file with a different name. From the file system's point of view, there was nothing left to find. From the server's point of view, the infection was very much running.
3. Web workers stuck in a loop, and a payload kept in shared memory
The most stubborn case involved three WordPress sites on the same hosting account. Every component was removed from all three in the same second, and in under a minute everything was back, including a fake plugin from one site turning up in the other two.
No executable was left on disk. Two background PHP programs were running, which was expected, but killing them didn't help. The rest of the engine lived inside the web server's own PHP workers: two of them had used close to 40 minutes of processor time over 48 minutes of life, stuck in a loop instead of waiting for visitors the way a healthy worker does. Five blocks of shared memory, each about the size of the kit's core file, held the full payload ready to be written back.
Only stopping the processes, clearing that memory and deleting the files together, in a single run, stopped the reinfection. After that, the site stayed clean through several minutes of continuous traffic.
4. A scheduled task that ignores your firewall
On another site, there was no background program at all. Instead, an entry in the hosting account's scheduled tasks ran the payload every five minutes and put itself back when removed. Fake plugins kept rewriting wp-config.php and the must-use plugins on every page load, and the site's legitimate administrator had been quietly downgraded to a lower role.
Blocking web access stopped only half of it. Scheduled tasks don't go through your web server, so firewall rules and .htaccess restrictions never touch them.
5. A theme block with no fingerprint
Earlier versions of this family marked their code with labels, which made the infected section of a theme file easy to find. A newer version dropped them. On one site the injection in the active theme's functions.php was a short block of about 50 lines, lightly scrambled, appended after the legitimate code and printing the JavaScript for a fake "verify you are human" page. Searching for the old labels found nothing. What gave it away was the database list of restore points, which named that theme file.
6. Disguises aimed at the person cleaning up
The fake plugins carried names chosen to discourage deletion, including two named after a well-known security company and labeled as a system plugin that must not be removed. On another site, a new administrator account appeared while the cleanup was in progress. It had never logged in, and it was named to look like it belonged to a backup plugin that really was installed on that site.
Signs the engine lives outside your files
The first clue is an empty search. If a careful search right after the cleanup finds no infected file anywhere, and everything still comes back, the copy doing the rebuilding isn't on disk. Speed alone doesn't tell you much here, because file-based versions of this family can also rebuild in well under a minute.
The second clue is that it comes back while the site is offline or blocked. If you put the site behind a maintenance page or deny all web traffic and files still reappear, the work is being done by something that doesn't need a visitor at all.
The third is spread. When a fake plugin removed from one site shows up on another site in the same hosting account, the copy doing the writing has access to the whole account, which a single infected file inside one site normally doesn't.
Indicators to check
These belong to the malware itself, not to any particular site:
- Database settings whose names start with
sc_, including temporary entries such as_transient_sc_guard - Scheduled WordPress events named
sc_cron_fetchorsc_cron_guard - A hidden folder in
wp-contentwhose name starts with.sc_ - A
wp-content/object-cache.phpof a few dozen bytes containing the commentSCOCV - A data file named like
.wp-object-cache-followed by random characters - Zip files with eight-character hexadecimal names in
wp-content, in theme folders or inuploads - A process with
--sc-cliin its command line
The honest takeaway
The usual advice for self-healing malware, inventory everything and remove it in one pass, is still correct. It just isn't sufficient once the engine is running. A cleanup that touches only files and the database can be flawless and still lose, because the copy that matters was never in either place.
The reverse mistake is just as common: blaming "other sites on the server" when the infection keeps returning. On one account where that was the theory, the supposedly infected neighboring sites turned out to be empty folders. The real reinfector was a single background process.
What to do next
If an infection returns within a minute of a complete cleanup, stop deleting. Each round only gives it something to rebuild.
Open your hosting control panel's scheduled task list (often labeled Cron Jobs) and look for anything you didn't create, especially entries that run every few minutes. Then ask your host's support to check for long-running PHP processes under your account and to restart PHP for your site. They can see the process list even when you can't.
Check your WordPress users for administrator accounts created recently, and check your active theme's functions.php for code added at the end that you don't recognize. Compare the plugin folders on disk with the list in your dashboard, since the dashboard can be manipulated.
Once the running copy is stopped and everything is removed in one pass, watch the site for several minutes. Then change every administrator password, your hosting password and your database password, because one variant of this family also captures login details typed into the admin area.
Kornet is built for exactly this kind of infection: the scanner reads every file and the entire WordPress database in one pass, so the restore points that would otherwise rebuild each other are found together, and the report shows everything it touched. The scan is free; you only pay if we actually find malware.
Kornet Labs publishes field notes from real WordPress malware cleanups. The behavior described here was documented across several infected sites on different hosting providers, all running newer versions of the same malware family.
