Anonymized case study. Client names, domains and identifying details are removed. Work carried out in July 2026.
In July 2026, a nonprofit received a formal notice from its bank's payment services team. The organization's website was linking to risky or illegal financial services, and it had ten days to respond.
We checked the website and confirmed the issue. It contained hidden payday-loan spam and a separate cloaking kit designed to hide its activity from administrators.
There was also a more urgent problem. An attacker had successfully logged in using a valid administrator password three weeks before our audit. Removing the spam was not enough. We had to deal with access first, then clean the website and verify the changes.
What we found
The organization had three WordPress installations, one for each language, running under the same hosting account. Our investigation identified several problems.
Hidden spam link
The theme's header.php contained an HTML link pointing to a payday-loan website. The link had no visible text, so visitors did not see anything unusual on the page.
However, the link was still present in the HTML of every page on one language version. Search engines and the bank's scanner could read it even though it was invisible to ordinary visitors.
The link had been there for about two and a half years. We also found an identical infected copy inside a theme backup folder. Restoring that backup would have put the spam straight back.
Cloaking doorway kit
On another installation, five files had been placed inside wp-includes/pomo/, a core WordPress directory that few people normally inspect.
Together, the files ran a spam operation. They included a PHP controller, a large encoded collection of spam pages, a spam sitemap, a template and a log of visitor data.
All five files were publicly reachable. The controller served spam to search engines and referral traffic but returned a 404 page to logged-in WordPress users.
This explained why administrators checking the website through WordPress could see nothing wrong while the malicious content remained accessible to other visitors.
Spam in the database
We also found thousands of spam references in old post revisions.
These references were not live on the website, but they were still stored in the database. Restoring one of the affected revisions could have republished the spam.
An attacker with valid credentials
The login logs showed a successful administrator login from a data-center IP address associated with known abusive hosting. There were no failed login attempts before it.
After logging in, the attacker performed automated searches for payment data.
The likely source of the password was a full database backup, several gigabytes in size, stored in a publicly downloadable folder on the web server.
Why the website was exposed
The installations were running WordPress versions that had been unsupported for years, a PHP version unsupported since 2018, and plugins that were eight to twelve years old.
The account setup also needed attention. Sixteen of the 23 user accounts had administrator privileges, and several used email addresses belonging to former agencies.
One of those email domains was close to expiring. Whoever registered it next could potentially have used it to reset the administrator's password.
What we did
We divided the work by urgency. We also advised the client to hold its response to the bank until the first phase had been verified.
Immediate actions, P0
- Rotated every WordPress password, the security keys and salts on all three installations, plus the FTP, hosting panel and database passwords.
- Removed the publicly accessible database backups from the web root.
- Deleted the cloaking kit and the injected link, including the infected copy in the theme backup.
- Cleaned the spam references from the database revisions.
Next actions, P1
We patched a header-injection flaw in a contact form script, reduced the number of administrator accounts, moved former agency accounts to email addresses controlled by the organization, and restricted the FTP account.
Longer-term actions, P2
We recommended rebuilding the installations on supported WordPress and PHP versions. Cleaning an unsupported stack does not remove the underlying exposure to known vulnerabilities.
We delivered an executive report for the organization's leadership, including the findings, the remediation plan and guidance for responding to the bank. We also provided a technical forensic report containing the evidence.
We made the limits of the investigation clear. Thirty days of logs could not prove that no earlier access had occurred.
What we changed in our own process
Our first pass missed the hidden spam link. It was plain HTML, and the initial scan focused on obfuscated code.
The bank's alert sent us back for another review. That second pass uncovered the link, the cloaking kit and the attacker's successful login.
We now include searches for plain-text spam and unexpected outbound links, rather than focusing only on obfuscated PHP. Our guide to removing the "This site may be hacked" warning covers related checks.
What website owners should take away
- Keep database backups outside the web root. A publicly downloadable database dump can expose password hashes and other sensitive information.
- Reduce the number of administrators. Every administrator account creates another potential way into the website. Remove unused accounts and use email addresses on domains the organization controls.
- Keep WordPress, PHP and plugins supported. Cleaning an old installation does not fix its underlying vulnerabilities. Our WordPress maintenance plan checklist covers version maintenance.
When to get help
If your bank, hosting provider or Google has flagged your website, the deadline matters, but so does the order of work.
Start by securing access and rotating credentials. Then remove the malicious content, check the database and verify the cleanup.
Our WordPress malware removal service follows this approach, starting with access and credentials before cleaning and verification.
