A business WordPress website in Vietnam was flooded with 119 casino spam posts, seeded with 4 rogue administrator accounts, and carried a backdoor that re-created its own files after deletion. This post records the symptoms, the order of the cleanup, and the traps that make cleanups fail, so you can follow the same path if your site shows the same signs. Most steps need only WordPress admin access, no SSH.
Signs that your WordPress site has been injected with spam
Owners usually notice only when Google Search Console raises a flag, or when someone finds the brand name next to gambling keywords. In this case the signs were:
- Strange posts in the sitemap: open
/post-sitemap.xmland you find hundreds of French or English URLs containingcasino,1xbetorapk. The total is far higher than the number of posts you actually wrote. - Back-dated publish dates: the spam carried dates from May to July, but their post IDs sit right after your most recent real posts. The ID is more reliable evidence than the date.
- Hidden links on the homepage: view the page source and search for
font-size:0,clip-pathorleft:12000pxon<a>tags pointing to unknown domains. - Unknown accounts: the Users screen shows Administrators named like
rootorsupport_xxxx, or with@example.invalidemails. - Security plugin switched off: Wordfence or a similar plugin is Inactive and you did not turn it off.
A backdoor hidden in mu-plugins: why deleting it once is not enough
The wp-content/mu-plugins/ folder holds “must-use” files. WordPress runs them automatically and they do not appear in the normal Plugins list. To see them, go to Plugins and open the Must-Use tab. Here there were 3 suspicious files: a small one that printed hidden links into the page, and two identical files (about 27 KB each) calling themselves a “Recovery Channel”.
The comments inside the code state its purpose: to stop a “competitor who bought admin access to the shared site” from removing it. Its configuration lives in wp_options rows with disguised names, so it survives even when the main plugin is deleted. The practical result: when I deleted the two files, they were re-created within seconds.
| Location | What to look for |
|---|---|
wp-content/mu-plugins/wp-<12 hex chars>.php | No plugin name, unusually large, makes connections to an outside domain |
wp-content/request.php | A 1 KB file containing eval( and $_POST: a webshell that runs remote commands |
Unfamiliar folders in wp-content/ | Random-named folders, hidden folders starting with a dot, “-prev” folders |
| A plugin that just appeared | Name resembles a legitimate function (“script booster”, “link helper”), unknown author |
| Timestamps | New files appearing after you started cleaning: the attacker still has access |
An 8-step process when you only have admin access
- Back up and capture the current state: export the database and write down the user list, plugins and mu-plugins. If your host keeps snapshots from before the breach, that is the cleanest option, so ask the provider first.
- Delete rogue admins: Users, select each unknown account, Delete, and choose “Attribute all content to” a main account (do not choose Delete all content, so you keep the evidence).
- Revoke Application Passwords: open each user profile, scroll to Application Passwords, Revoke all. Change passwords and enable 2FA on every remaining account.
- Find the malware: check the Must-Use tab, the
wp-content/folder and unfamiliar plugins. Scan with Wordfence (a free license registration is required). File-manager plugins can list folders, but outdated ones are also an entry point, so do not keep them. - Remove the whole set in one pass: webshell, main plugin, odd folders, mu-plugin files. Wait 30 seconds, load the homepage and wp-admin to trigger any self-healing mechanism, then list the folders again to confirm nothing was re-created.
- Move spam posts to trash (not permanent delete): filter by post ID and verify every slug really is spam first. For large volumes use the REST API
DELETE /wp-json/wp/v2/posts/{id}from an admin session; by default it only moves posts to trash. - Clear caches and re-check the sitemap: Empty All Caches (W3 Total Cache, LiteSpeed, WP Rocket…), reopen the sitemap to confirm no spam URLs remain, and check the homepage for hidden links.
- Monitor for 7 days: each day check Must-Use, the Users list and the sitemap URL count. A new post or file means the entry point is not yet closed. In Search Console resubmit the sitemap and use Remove URLs for the spam URLs.
Traps you are likely to hit
- Spam URLs still return HTTP 200 after deletion: the theme sends every missing URL to the homepage (a soft 404). Google takes longer to drop them. Configure a real 410 or 404.
- The security plugin’s Activate button “does nothing”: in this case the admin page was simply too heavy (the plugin did activate, but the page took tens of seconds to respond). Wait and reload the list before clicking again; if it still will not activate, suspect code that blocks security plugins.
- Bulk trash returns a 500 error but the posts are in the trash: the error happens when rendering the page after the action. Always check the post status before repeating.
- Changing the password is not enough: while a webshell remains, the attacker does not need your password. After the site is clean, also change the salts in
wp-config.phpto invalidate every login session.
Results after cleanup
- Accounts: 8 users down to 4, with only 1 Administrator.
- Spam posts: 119 posts moved to trash,
post-sitemap.xmlreduced from 514 to 395 URLs, 0 URLs containing spam keywords. - Malware: 5 components (webshell, main plugin, odd folders, 2 self-healing mu-plugins) removed in one pass, no file reappeared after 30 seconds.
- Homepage: the block of hidden links pointing to 10 casino domains is gone.
Still open at the time of writing: registering the Wordfence license for a full scan, cleaning the disguised wp_options rows (needs phpMyAdmin), changing the database and hosting passwords, and updating 20 outdated plugins. If your host has a snapshot from before the breach, restoring it is still the neatest option.
Does your website show similar signs?
I take at most 3 new consulting projects a month. Send me your domain and I will check your sitemap and homepage for free in the first session.