WordPress malware is any code added to your site without your knowledge that serves someone else’s purpose. It might redirect your visitors to scam sites, inject spam links into your pages, skim payment details from your checkout, send email from your server, or quietly mine cryptocurrency using your server’s resources. The code is usually hidden in PHP files, the database, or both.
The WordPress ecosystem’s openness – thousands of plugins, themes, and extension points – is what makes it powerful and what makes it a target. Attackers do not manually hack individual sites. They identify a vulnerability in a plugin, write a script that exploits it, and run that script against every WordPress site on the internet. If your site has the vulnerable plugin, it gets hit whether anyone knows your site exists or not.
How malware gets into WordPress#
Plugin and theme vulnerabilities
This is the most common entry point. A plugin with a file upload vulnerability, SQL injection, or broken access control gives an attacker a way to execute their code on your server. The attacker does not need your credentials. They do not need to log in. They exploit the vulnerability directly through HTTP requests.
The scale of this problem is significant – over 250 WordPress plugin vulnerabilities are reported every week. Most are in plugins you have never heard of, but popular plugins with millions of installations get hit too. A single unpatched vulnerability in a widely used plugin can result in thousands of compromised sites within days of disclosure.
The attack chain is predictable:
- Vulnerability is disclosed or discovered by attackers
- Automated scanners identify sites running the vulnerable version
- The exploit runs, typically uploading a PHP backdoor or injecting code into existing files
- The attacker establishes persistence so they maintain access even after the original vulnerability is patched
Compromised credentials
Brute force attacks against wp-login.php and xmlrpc.php are constant. Automated bots cycle through common username/password combinations against every WordPress login page they find. If your admin password is weak or reused from another service that was breached, this is how they get in.
Once they have admin access, they install a backdoor disguised as a plugin, modify theme files to include their code, or create a hidden admin account. The original login credentials become irrelevant once persistence is established.
Credential stuffing – trying email/password combinations leaked from other data breaches – is particularly effective because people reuse passwords. An attacker who buys a database of breached credentials tests them against WordPress login pages at scale.
File upload exploits
Some plugins allow file uploads (contact form attachments, media uploads, import tools) without properly validating file types. An attacker uploads a PHP file disguised as an image or document. Once that file is on the server and accessible via a URL, they can execute arbitrary PHP code.
Even plugins that validate file extensions can sometimes be bypassed. Double extensions (
.php.jpg
), null bytes in filenames, and MIME type spoofing are common techniques. A web application firewall catches many of these patterns, but they are not foolproof against crafted payloads.
Supply chain attacks
A plugin developer’s account on wordpress.org gets compromised, and the attacker pushes a malicious update through the official update system. Every site running the plugin installs the malicious version automatically (or is prompted to update). The malware arrives through a trusted channel, signed and distributed by WordPress’s own infrastructure.
This is rarer than direct vulnerability exploitation but harder to defend against because the malware is delivered through the same mechanism as legitimate updates. Reviewing plugin changelogs and waiting a few days before applying updates from less-established plugins can help, but there is no perfect defense against a compromised supply chain.
Nulled themes and plugins
“Nulled” or “cracked” premium plugins and themes – pirated copies distributed for free on shady download sites – almost always contain embedded malware. The person who cracked the plugin adds their own backdoor before redistributing it. Installing a nulled plugin is essentially handing your site to an attacker voluntarily.
Signs your site is infected#
If you are seeing any of the symptoms below and need to act immediately, see my WordPress site was hacked: what to do right now for the emergency response steps.
Unexpected redirects
Visitors are sent to a different site – gambling pages, fake tech support, pharmaceutical spam, or malware download pages. The redirects often target only visitors coming from search engines (checking the HTTP referer header) so the site owner does not notice when visiting directly. Some malware only redirects mobile visitors or visitors from specific countries.
Spam content in search results
Your site appears in Google search results with titles and descriptions you did not write – typically pharmaceutical keywords, gambling terms, or adult content. This is SEO spam injection. The malware creates hidden pages or modifies your existing content so search engines see the spam but your regular visitors see the normal site (cloaking).
Check by searching
site:yourdomain.com
in Google. If you see pages or titles that do not belong to you, your site is compromised.
Google warnings
Google Search Console sends a notification that your site contains malware or unwanted software. Google’s Safe Browsing may display a full-page warning to visitors before they reach your site. This warning dramatically reduces traffic and takes time to remove even after the malware is cleaned up.
Hosting provider suspension
Your hosting provider suspends your account because their malware scanner detected malicious files, your site was sending spam email, or your site was participating in attacks against other servers. Hosting providers monitor for this because a compromised site on their network affects their IP reputation and other customers.
Slow performance or high resource usage
Malware that mines cryptocurrency or sends spam consumes CPU, memory, and network bandwidth. If your site’s resource usage suddenly spikes without a corresponding increase in legitimate traffic, malware is a possible cause.
Unknown admin accounts
Check your WordPress user list. If you see admin accounts you did not create – especially with generic names like “admin2”, “support”, or random strings – an attacker has been there.
Modified files
Core WordPress files, plugin files, or theme files have been changed. WordPress does not modify its own files between updates. If
wp-includes/version.php
or any core file has a recent modification date that does not correspond to a WordPress update, something changed it.
How to detect malware#
Wordfence scanner
Wordfence includes a malware scanner that compares your WordPress core files, plugin files, and theme files against known-good versions. It also checks for known malware signatures, suspicious file patterns, and backdoor indicators.
Install Wordfence (the free version includes the scanner), go to the Wordfence dashboard, and run a full scan. The scanner reports:
- Modified core files (files that differ from the official WordPress release)
- Modified plugin and theme files
- Files that match known malware signatures
- Files in unexpected locations
- Suspicious code patterns (base64 encoding, eval(), gzinflate(), and other functions commonly used by malware)
Wordfence’s scanner is effective against known malware, but it has limitations. Novel malware that does not match existing signatures will not be detected until Wordfence updates its database. Obfuscated code designed to evade signature matching may slip through.
Sucuri SiteCheck
Sucuri’s free remote scanner (sitecheck.sucuri.net) checks your site from the outside. It loads your homepage and checks for known malware indicators, blocklist status, and security issues visible in the HTML output. It catches JavaScript-based malware, injected iframes, and spam links that are rendered on the page.
The limitation of remote scanning is that it only sees what a regular visitor sees. Malware that activates conditionally (only for search engine crawlers, only for mobile visitors, only on specific pages) may not be visible to the scanner.
Manual file inspection via SSH
For a thorough investigation, connect to your server via SSH and inspect the filesystem directly. This catches things that automated scanners miss.
Find recently modified PHP files:
find /path/to/wordpress -name "*.php" -mtime -7 -type f
This lists every PHP file modified in the last 7 days. Cross-reference these with your known changes (plugin updates, theme edits). Any PHP file that was modified but should not have been is suspicious.
Search for common malware patterns:
grep -rl "eval(base64_decode" /path/to/wordpress/
grep -rl "eval(gzinflate" /path/to/wordpress/
grep -rl "eval(str_rot13" /path/to/wordpress/
grep -rl "assert(base64_decode" /path/to/wordpress/
These patterns are overwhelmingly associated with malware. Legitimate plugins rarely use
eval(base64_decode())
. If you find this pattern in a file, read the file and determine whether the code is part of the original plugin or was injected.
Check for PHP files in the uploads directory:
find /path/to/wordpress/wp-content/uploads -name "*.php" -type f
The uploads directory should contain images, documents, and media files. PHP files in the uploads directory are almost always malware. WordPress does not put PHP files there during normal operation.
Check for hidden files and directories:
find /path/to/wordpress -name ".*" -type f
ls -la /path/to/wordpress/wp-content/plugins/
Malware sometimes hides in dotfiles (files starting with
.
) or directories with names designed to look legitimate.
Check wp-config.php for injected code:
head -20 /path/to/wordpress/wp-config.php
tail -20 /path/to/wordpress/wp-config.php
Malware is sometimes injected at the very beginning or very end of wp-config.php. The file should start with
<?php
and contain only database credentials, authentication keys, and WordPress configuration constants.
Database inspection
Some malware lives entirely in the database, not in files. It is stored in the
wp_options
table (as a widget, a transient, or a rogue option) or injected into post content.
Check for suspicious content in options:
SELECT option_name, option_value FROM wp_options WHERE option_value LIKE '%eval(%' OR option_value LIKE '%base64_decode%' OR option_value LIKE '%<script%';
Check for injected scripts in posts:
SELECT ID, post_title FROM wp_posts WHERE post_content LIKE '%<script%' AND post_content LIKE '%document.cookie%';
Check for rogue admin users:
SELECT u.ID, u.user_login, u.user_email FROM wp_users u INNER JOIN wp_usermeta m ON u.ID = m.user_id WHERE m.meta_key = 'wp_capabilities' AND m.meta_value LIKE '%administrator%';
Review the results. Any admin account you do not recognize needs to be deleted.
Cleanup process#
Step 1: Take a backup before cleanup
Before changing anything, back up the current state of the site – files and database. Even though the site is compromised, you want a snapshot of the infected state in case you need to analyze it later or in case the cleanup goes wrong.
Step 2: Identify the entry point
Before removing malware, understand how it got in. If you clean up the files but leave the vulnerability that was exploited, the attacker comes back through the same hole within hours.
Check:
- Were any plugins outdated at the time of infection? Check plugin versions against disclosed vulnerabilities.
- Were there brute force login attempts in the access logs?
- Were any suspicious file uploads logged?
- Did anyone on the team install a nulled plugin or theme?
Step 3: Update everything
Update WordPress core, all plugins, and all themes to their latest versions. If a plugin was the entry point and a patched version is available, updating closes the vulnerability. If no patch exists, deactivate and delete the plugin.
Step 4: Remove the malware
Replace WordPress core files. Download a fresh copy of your WordPress version and replace the entire
wp-admin/
and
wp-includes/
directories. These directories should contain only official WordPress files. Do not replace
wp-content/
– that contains your themes, plugins, and uploads.
# Download fresh WordPress
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
# Replace core directories
rm -rf /path/to/wordpress/wp-admin
rm -rf /path/to/wordpress/wp-includes
cp -r wordpress/wp-admin /path/to/wordpress/
cp -r wordpress/wp-includes /path/to/wordpress/
Reinstall plugins from clean sources. Delete each plugin directory under
wp-content/plugins/
and reinstall from wordpress.org or the vendor. Do not attempt to clean infected plugin files – a fresh install is faster and more reliable.
Check theme files. If you use a theme from a known source, reinstall it. If you use a custom theme, review every PHP file for injected code. Pay attention to
functions.php
,
header.php
, and
footer.php
– these are the most common injection targets in themes.
Clean the uploads directory. Remove any PHP files found in
wp-content/uploads/
. Remove any files with suspicious names or double extensions.
Clean wp-config.php. Compare your wp-config.php against a clean template. Remove any code that does not belong (typically injected at the top or bottom of the file). Regenerate your authentication keys and salts using the WordPress salt generator.
Remove backdoor user accounts. Delete any WordPress admin accounts you did not create. Reset passwords for all remaining admin accounts.
Step 5: Check the database
Run the SQL queries from the detection section above. Remove any injected scripts from post content, delete rogue options, and clear any suspicious transients:
DELETE FROM wp_options WHERE option_name LIKE '_transient_%' AND option_value LIKE '%eval(%';
Step 6: Reset all credentials
- Change all WordPress admin passwords
- Change the database password (update wp-config.php to match)
- Change FTP/SFTP passwords
- Regenerate WordPress authentication keys and salts
- Revoke and regenerate any API keys used by plugins
If the attacker had access to wp-config.php, they have your database password. Changing it is not optional.
Restoring from backup vs manual cleanup#
When to restore from backup
Restoring a known-good backup is the fastest and most reliable cleanup method when:
- You have a backup from before the infection occurred
- You know when the infection started (so you can choose the right backup)
- The backup includes both files and the database
- You have verified the backup is actually clean
The process: restore the backup, immediately update all plugins and WordPress core, change all credentials, and verify the vulnerability that was exploited has been patched.
When to clean manually
Manual cleanup is necessary when:
- You do not have a clean backup
- You do not know when the infection started (the malware might be in all your backups)
- The site has had significant content changes since the last clean backup and restoring would lose that content
- You need to understand the full scope of the compromise for reporting or compliance reasons
Manual cleanup takes longer but gives you visibility into exactly what was changed and how.
The hybrid approach
Restore core WordPress files and plugins from clean sources (fresh downloads), keep your database and uploads (after cleaning them), and keep your wp-config.php (after removing injected code and rotating credentials). This gets you the reliability of fresh files with the data preservation of manual cleanup.
Hardening after cleanup#
Cleaning up malware without hardening the site is a temporary fix. The same vulnerability or another one will be exploited again.
Keep everything updated
The single most effective hardening measure. Set up a process to apply WordPress core, plugin, and theme updates promptly. Most malware infections exploit known vulnerabilities that have patches available. Automatic updates for minor WordPress releases and plugin security patches reduce the window between disclosure and patching.
Remove unused plugins and themes
Every installed plugin is attack surface, even if it is deactivated. Deactivated plugins can still be exploited if their files are accessible via direct URL requests. Delete any plugin or theme you are not actively using.
Use strong, unique credentials
Use a password manager. Do not reuse passwords across services. Enable two-factor authentication on all admin accounts. This eliminates brute force and credential stuffing as attack vectors.
Limit admin accounts
Only give administrator access to people who need it. Use the Editor or Author role for content creators. Every admin account is a high-value target.
Monitor file integrity
Use a security plugin that monitors file changes and alerts you when WordPress core files, plugin files, or theme files are modified outside of an update. Early detection limits the damage.
Use a web application firewall
A WAF blocks common attack patterns – SQL injection, XSS, file upload exploits, path traversal – before they reach your application. This does not replace patching, but it blocks the automated exploitation tools that account for the vast majority of WordPress attacks.
WordPress malware and container isolation#
On traditional shared hosting, a compromised WordPress site is not just a problem for that site. If the server does not properly isolate accounts, the attacker can pivot from your compromised site to other accounts on the same server – reading their files, accessing their databases, or using their resources.
Container isolation changes this fundamentally. When each hosting account runs in its own container with separate process namespaces, filesystem mounts, and network namespaces, a compromised WordPress site is contained to that single container. The attacker gets access to your site but cannot see or reach anything else on the server.
This does not prevent the malware from damaging your site. But it limits the blast radius. A compromise affects one site, not every site on the server. For the hosting provider and other customers on the same server, your infection is invisible.
WordPress malware on Hostney#
On Hostney, multiple layers work together to prevent, detect, and contain malware:
- Bot detection blocks automated vulnerability scanners and exploit tools before they reach your site
- ModSecurity with the OWASP Core Rule Set blocks SQL injection, XSS, file upload exploits, and other attack patterns at the web server level
- Container isolation ensures a compromised site cannot affect other accounts
- Real-time malware protection monitors file system changes and detects malicious files as they are created or modified. The malicious file is quarantined automatically and the incident is reported to the control panel so you have immediate visibility into what happened
- Automated backups provide restore points for recovery
- File permission enforcement prevents WordPress from modifying files it should not need to modify
If your site on Hostney is showing signs of infection, contact support. The team can check ModSecurity logs to identify when and how the compromise occurred, help with cleanup, and add any necessary WAF rule exclusions or hardening measures specific to your site.