Evidence before cleanup
Nothing changed on the server until the backup was verified and the findings were reported.
WordPress incident response
A Polish legal and accounting firm suspected that its WordPress sites had been hacked. We backed everything up, traced the attack, removed the spam and closed every path the attacker had used.
The firm runs three WordPress sites on one shared hosting account: a corporate site, a services site and a help centre. Nobody knew how deep the problem went, and nobody wanted a cleanup that would destroy the evidence.
“The sites are hacked, at least one. Back them up, scan files and databases. Do not change anything yet.”
01
02
Every spam edit came from a genuine administrator account after a normal login that succeeded on the first try. Brute force was running too, but the attacker already had the password. The two clean sites shared the same administrators.
First hidden link inserted on the home page.
Payday loan, casino and crypto exchange links added in two more waves.
The services page gets a block of Lithuanian casino links.
Last edit to the home page, from an AWS IP address.
Backup, investigation and cleanup begin.
Files, databases, access logs and old archives from all three sites, about 10 GB, copied locally before any analysis. The databases were saved byte for byte so Polish and Cyrillic text could be restored exactly.
WordPress core was compared file by file with the official release. Plugins, themes, uploads and mu-plugins were scanned for web shells, databases for hidden blocks and foreign admins, logs for logins and edits. We also checked what Googlebot sees to rule out cloaking.
30 spam blocks removed from 11 database records, including 9 old revisions, so the spam cannot come back through a revision restore. Each update was checked against the record hash, and the visible page text was left unchanged.
Public archives deleted, a fake plugin and a backdoor folder removed, xmlrpc.php blocked, security keys rotated to end every session, database passwords changed. A stranger’s email that received password resets was replaced in 15 places.
Remote code execution in WPML (CVSS 9.9) and arbitrary file read in Smart Slider 3 Pro closed with one-line patches. A crashed admin panel fixed. Updates reconfigured, and two-factor login made mandatory for every admin and editor.
03
Nothing changed on the server until the backup was verified and the findings were reported.
Each change was proposed, approved by the client and only then applied.
Every edited file and table was saved first, so each step can be reverted in minutes.
When the client wanted a removed file manager back, it was restored from the backup in a minute.
04
Two old archives in the public web root of the main site returned HTTP 200 to anyone who guessed the URL. Archives like these usually contain wp-config.php with database passwords. We cannot prove this is how the admin password leaked, but it was the most likely candidate. The archives now return 404.
Access was SSH plus the cPanel UAPI. Work was done through WP-CLI and direct SQL over a latin1 connection, with byte-level replacement and MD5 checks so multilingual content stayed intact.
The spam was hidden with position:absolute and offsets such as left:-503011px, plus white or 8–12 px text. Two copies had been pasted as escaped HTML, so visitors could see raw code on the home page.
Patches: WPML no longer renders language-switcher shortcode content as a Twig template (CVE-2024-6386). Smart Slider 3 Pro export now requires edit permission and a security token (CVE-2026-3098).
Two-factor login uses an authenticator app (TOTP) with backup codes and a 30-day grace period. Admins received a one-page PDF guide with screenshots and the QR codes blurred.
The investigation was run by an AI coding agent working over SSH under human control. The agent did the log analysis, file comparison and database work. People made every decision and approved every change.
Suspect your WordPress site has been compromised?