CMS malware: why reinfections happen and how to prevent them for good

By Kike Gandia · Co-Founder & CEO, OSCP

Reinfection is the most frustrating pattern in CMS compromises: the site is cleaned, and malware reappears within days or weeks. It happens because surface-level cleaning removes neither the original entry vector nor the persistence mechanisms the attacker installed. This guide explains the reinfection cycle and how to break it.

Why compromised CMS sites get reinfected

CMS malware cleanup has two layers: removing the visible malicious code and closing the entry vector that allowed the initial compromise. Most surface-level cleanups only do the first part.

When the original entry vector isn't closed —a vulnerable plugin, compromised credentials, a web shell in an uploads directory— the attacker can reinstall the malware within hours or days. In sophisticated compromises, the attacker leaves multiple persistence mechanisms: web shells in unusual paths, hidden administrative users, scheduled tasks (cron) that reinstall the malware, modifications to the CMS core and malicious code in theme files.

Common types of CMS malware

PHP web shells: PHP files that give the attacker remote control of the server. They are disguised with filenames resembling those of the core (wp-feed.php, class.db.php) or injected into legitimate files.

SEO spam: Injection of links to spam sites into the site's content (invisible to the visitor, visible to Google). It destroys organic rankings and can lead to deindexing.

Malicious redirects: The visitor is redirected to phishing pages, malware downloads or scams. Often conditioned on the user-agent (only affecting visitors on mobile, from Google, etc.).

Card skimmers: Malicious JavaScript injected into the checkout that captures payment data.

Cryptominers: Scripts that use the visitor's CPU to mine cryptocurrency in the background.

The correct remediation process to prevent reinfections

1. Identify the entry vector: Without knowing how the attacker got in, cleanup is only temporary. Analysis of access logs, review of files modified during the compromise window and cross-referencing against the CVE history of installed plugins.

2. Inventory every persistence mechanism: Web shells, unauthorised administrative users, malicious cron tasks, modifications to the core and to configuration files.

3. Restore from a verified clean backup: If there's a backup predating the compromise (and verified as clean), restoring it is more reliable than cleaning manually. The backup must be applied after the entry vector is closed to avoid restoring the compromised state.

4. Close the original entry vector: Update or remove the vulnerable plugin or module, change all credentials (CMS, hosting, database, FTP), review file permissions and apply hardening.

5. Verify the cleanup: Scan with multiple tools and manually review the directories where persistence is most common.

FAQ

Is a malware scanner enough to confirm the site is clean?

No. Automated scanners detect known malware signatures. An attacker with access can obfuscate the code to evade signatures or inject it into legitimate files in positions the scanners don't analyse in depth. Manual review of modified files and access logs is necessary.

Do you have to notify users if the site was compromised?

It depends on the type of data exposed. If the compromise affected users' personal data, the GDPR requires notifying the supervisory authority within 72 hours of detection and potentially the affected individuals. If it was only malware injection without access to data, the notification obligation depends on the forensic analysis of the scope.

Related service

CMS pentesting and audit service

Related content

Sources

Request a CMS compromise assessment