Your host just emailed you about spam.
Maybe it's a suspension warning. Maybe your inbox is filling up with bounce-backs for emails you never sent. Either way, something is using your WordPress site to send mail you didn't write.
A spam mailer script doesn't deface your pages or lock you out of the dashboard, so the site still loads fine. But it can get your hosting account suspended and your domain blacklisted within days. It's a close cousin of the redirect hack, same motive, different delivery method.
Most guides stop at "scan your site for malware." That tells you what happened. It doesn't tell you where to look. This one does. We follow the same order we'd use on a client site: confirm the spam is really coming from your server, find the script responsible, then remove it properly.
Two Things This Is Not (Check These First)
Before you go looking for a file, rule out two causes that have nothing to do with a hacked website.
The first is spoofing. Spammers forge the "From" address on outgoing mail all the time, and any domain can be a target. Your server never touches the message, it just gets your name put on it. Open one of the spam samples and check the "Received: from" chain in the headers. If none of the hops trace back to your own hosting IP, it's spoofing. There's no script to find.
The second is a compromised email account. If your team sends mail through a real provider like Google Workspace or SendGrid, and a password or API key gets stolen, spam goes out through that provider using your credentials, no file gets planted anywhere. The fix is a password reset and a new API key, not a malware scan.
If neither fits, something is running on your server. Time to find it.
Confirm It's Actually Your Server
Ruling out those two doesn't prove the spam comes from your hosting account. Volume does.
Most cPanel hosts have a delivery report, usually called Track Delivery, that shows how many messages left your account and when. A spike you didn't cause is your answer. If WordPress's own wp_mail() function is doing the sending, installing WP Mail Logging for a few minutes shows every call and what triggered it.
Check the spam sample's headers once more, too. Some hosts add an X-PHP-Originating-Script line to outgoing mail. It names the script that sent the message, which can point you straight at the culprit.
Don't open a single file until you've confirmed real outbound volume. Otherwise you're debugging a problem you don't have.
Find the Mailer Script
Work through these four checks in order.
Turn On Server-Level Mail Logging
A malicious mailer doesn't need wp_mail() at all. It can call PHP's own mail() function directly, and anything that watches only WordPress will never see it. Server-level logging catches both.
With root access, add two lines to php.ini.
mail.add_x_header = On
mail.log = /var/log/phpmail.log
Restart PHP, then watch the log.
tail -f /var/log/phpmail.log
Every mail() call is now logged with the file and line that made it.
No root? Try a .user.ini file with the same two lines, pointing mail.log at a file inside your own account. If your host blocks that, ask for the outbound mail log covering the last 24 to 48 hours and mention the spam warning. It often shows which folder each message came from.
Search WordPress Files for Mail-Sending Code
With SSH access, search wp-content for calls to mail().
grep -r "mail(" wp-content --include=*.php
Then search for the usual obfuscation wrappers.
grep -rE "base64_decode|eval\(|gzinflate" wp-content --include=*.php
Both return plenty of harmless hits, since legitimate plugins use these functions too. You're hunting for a hit in a strange place or a file with a random name. No SSH? Ask your host to run these two searches for you.
One rule cuts through most of the noise fast. wp-content/uploads should never contain a .php file, apart from an empty index.php some plugins add. That folder exists for images and documents, nothing that executes. Any other PHP file there is guilty until proven otherwise.
Still nothing? List PHP files changed recently and compare against what you actually updated.
find wp-content -name "*.php" -mtime -14
Check Both Cron Layers
Two different clocks can run a mailer on a schedule, and they hide in different places.
Server cron shows anything your hosting account itself schedules. Check with crontab -l over SSH, or the Cron Jobs page in cPanel.
WordPress runs its own pseudo-cron through wp-cron.php, invisible to server cron. A plugin like WP Crontrol lists every scheduled task WordPress knows about, including ones a script quietly added.
Look for the Backdoor That Keeps It Coming Back
A planted mailer often has company. Check your WordPress users for an admin account nobody on your team created, and check FTP or SFTP for a login you don't recognize. Either one can be how the attacker gets back in after you clean up.
Don't trust the Users screen alone. On a client site we recovered, it showed a single admin, but the database still held capability records for five more accounts dating back to March 2025. We only found them by querying the database directly.
Found It. Now What
Copy the file off the server before you touch it. If your host or a client asks what happened, you'll want that copy, deleting first and asking questions later is how evidence disappears.
Then delete the file and close the door it came through: the rogue admin account, the unfamiliar FTP login, whatever you found in the last check. Deleting the mailer while leaving the backdoor only delays the next one.
Then rotate every credential that could have leaked: WordPress admin passwords, your hosting or cPanel password, FTP and SFTP logins, and any SMTP API keys in use. A mailer script can arrive alongside stolen credentials, not instead of them.
Finally, scan the whole site for anything else dropped in the same visit. Our guide to manually scanning and cleaning WordPress malware walks through it end to end.
Get Off the Blacklist and Warn Your Host
Removing the script doesn't undo the damage to your sending reputation. Two things to handle next.
Check whether your IP or domain landed on a blacklist. MXToolbox runs a free check in seconds; Google Postmaster Tools shows how Gmail rates your domain. If you're listed, submit a delisting request now that the script is gone. Requesting it before the cleanup is finished just gets you listed again.
Then message your host directly. Tell them what you found and what you removed. Suspensions tend to lift faster when you arrive with an answer instead of waiting for their next automated scan.
Stop It From Coming Back
Start with the uploads folder, the easiest fix on this list. Add a small .htaccess file inside wp-content/uploads that blocks PHP from running there.
<Files *.php>
Require all denied
</Files>
Images and documents load exactly as before. A planted script just stops working. Test the site afterward, since a handful of plugins store PHP files in uploads. That syntax is for Apache 2.4. Nginx ignores .htaccess entirely, and older Apache needs different rules. Our guide to hardening wp-config.php and .htaccess covers both.
Outdated plugins and themes are still how most WordPress compromises start. Updating alone isn't enough, but it closes the door before a mailer is ever planted. Our WordPress plugin security guide covers the rest.
Add an alert for new PHP files in uploads, and the next warning comes from your own monitoring instead of your host.
Closing
That host email felt like an emergency, but the fix is mechanical once you know where to look. Confirm the source, find the script, remove it, and close the door it came through.
If you would rather hand this off, get in touch and we'll run the whole process for you, from finding the script to closing the backdoor.