Security 7 min read

cPanel Server Sending Spam? Find and Stop the Source

Outbound mail flooding out of a server nobody logged into means something else is doing the sending. Here is how to find it and shut it down.

By BashPilot Team
BashEmail Email spam protection Keep outbound mail clean and off blacklists, automatically. Explore BashEmail

A cPanel server sending spam without anyone touching WHM almost always means one of three things: a compromised account, a hijacked contact form or plugin, or a cron job nobody remembers writing. The queue fills, the load climbs, and if you are unlucky your IP is already on a blacklist before you notice.

Confirm it is really your server, and how bad it is

Start with a queue count. If this number is in the thousands, or climbing while you watch, you have an active sender, not a stale backlog.

queue size
exim -bpc

Prints a single number: total messages currently queued.

exiqsumm breaks the queue down by domain, which tells you fast whether this is one account hammering one target or a genuine flood.

queue by domain
exim -bp | exiqsumm | tail -20

If most of the destination domains look like consumer webmail providers (gmail.com, yahoo.com, outlook.com, hotmail.com) in large volume, that is a spam signature, not normal customer traffic.

Find which account or script is doing it

Every message exim accepts from a local process gets a U= field in /var/log/exim_mainlog, naming the system user that submitted it. This is the single most useful line in the whole file, because it points straight at the cPanel account, bypassing any need to guess from sender addresses that are usually spoofed anyway.

rank senders by local user
grep -oP 'U=\K[^ ]+' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head -20

The user at the top with an implausibly high count is your account.

Once you have the username, check what is actually calling the mail function. Recently modified files are the fastest lead, since a compromise usually drops or edits a file within the last few days.

recently touched PHP files
find /home/USERNAME/public_html -iname '*.php' -mtime -5 -type f -printf '%T@ %p\n' | sort -rn | head -30

Also check cron. A surprising number of spam incidents are a scheduled task someone set up years ago on a script that has since been exploited, not a fresh upload.

the account's cron jobs
crontab -l -u USERNAME

Stop the bleeding

  1. 1

    Suspend the account

    This stops new mail from being accepted for that user immediately, in WHM under Account Functions, or whmapi1 suspendacct user=USERNAME reason='investigating outbound spam'. It does not touch mail already queued.

  2. 2

    Clear only that sender's queued mail

    Filter by the account's outgoing address pattern before removing anything. exiqgrep -i -f 'USERNAME@' | xargs -r exim -Mrm removes only messages sent from that address. Never pipe the whole queue into exim -Mrm without a filter.

  3. 3

    Remove or quarantine the offending file

    Move the malicious script or plugin out of the web root (do not delete yet, you may need it to understand how the account was compromised), then reset the account's cPanel and any application admin passwords.

  4. 4

    Check for a backdoor before you reopen the account

    A single cleaned file is rarely the whole story. Search for freshly created files with unusual permissions or names that look like base64-encoded PHP, which is the most common backdoor pattern.

quick backdoor sweep
grep -rl --include='*.php' -E 'eval\s*\(\s*base64_decode' /home/USERNAME/public_html

Not exhaustive, but catches the most common obfuscated backdoor shape.

Doing this once, carefully, on one server is a Saturday afternoon. Doing it every time a shared host flags an account, across a fleet of servers, is the actual job for a lot of hosting teams. BashEmail runs this same queue-and-sender triage automatically, flags the account before the IP gets blacklisted, and stops there for approval rather than suspending anything on its own.

In BashPilot

Triaging an outbound spam spike in BashPilot

app.bashpilot.com
queue on this server just jumped to 4000, find out who is sending it
BashPilot

Checked exim_mainlog on web03. One local user accounts for 3,812 of the queued messages in the last hour, all to consumer webmail domains.

UserQueuedTop destination
marketing_co3812gmail.com
billing_llc41outlook.com
suspend marketing_co and clear its queue, leave everything else
BashPilot

That suspends the account and removes only messages from marketing_co@ from the queue. Legitimate mail from other accounts is untouched. Confirm to proceed.

bash
whmapi1 suspendacct user=marketing_co reason='outbound spam investigation'
exiqgrep -i -f 'marketing_co@' | xargs -r exim -Mrm
Example output, not a screenshot of a specific customer's server.

Try this on one of your own servers.

Start free trial

Get off the blacklist

Clearing the queue stops the spam, it does not undo the reputation damage. Check your sending IP against the major lists before assuming you are done.

  • Look the IP up on mxtoolbox.com/blacklists or a similar aggregator to see which lists actually flagged it.
  • Most blacklists (Spamhaus, Barracuda, SORBS) have a self-service delisting form once the cause is fixed. Submit it, do not just wait.
  • Confirm the server's PTR (reverse DNS) record resolves to the same hostname exim announces in its HELO. A mismatch here gets flagged by receiving mail servers independently of any spam history.
  • Check SPF, DKIM and DMARC records under WHM's Email Authentication tool. A missing or broken DKIM signature makes every message from the domain look more suspicious, spam incident or not.

Verify it actually stopped

Do not close this out on the queue count dropping to zero once. Confirm the pattern is gone, not just the current backlog.

watch for new spam from the same user
watch -n 30 "grep -c 'U=USERNAME' /var/log/exim_mainlog"

If that count stays flat for an hour after the account is suspended and cleaned, the source is actually gone. If it keeps climbing, the account is still compromised, most likely a backdoor you missed, or the cron job is still active under a different mechanism (a scheduled task inside the application itself, not system cron).

Prevent the repeat

  • Set a per-account hourly send limit in WHM (Server Configuration > Tweak Settings > Max hourly emails per domain) so one compromised account cannot flood the whole server's reputation.
  • Enable cPHulk brute force protection if it is not already on, since a lot of these incidents start with a guessed cPanel or application admin password.
  • Keep CMS cores, plugins and themes patched. If you manage many accounts, a scheduled scan is worth more than reacting after the fact.
  • Alert on queue size, not just on a blacklist notification. By the time a blacklist notice arrives, the reputation damage is already done.
Share LinkedIn X
Questions

Frequently asked questions

How do I find which cPanel account is sending spam?

Grep `/var/log/exim_mainlog` for the `U=` field, which names the local system user that submitted each message: `grep -oP 'U=\K[^ ]+' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head`. The account with an unusually high count relative to its normal traffic is almost always the compromised one.

How do I clear the exim mail queue without losing legitimate mail?

Never run a blanket removal against the whole queue. Filter by the offending sender address first with `exiqgrep -i -f 'user@domain'` to list only that sender's message IDs, then pipe those into `exim -Mrm`. This clears the spam while leaving every other account's mail queued and delivering normally.

Why did my server get blacklisted with no warning in WHM?

WHM has no built-in visibility into external blacklists, it only shows local queue and delivery status. Blacklisting happens on the receiving mail providers' infrastructure, so you only find out by checking a lookup tool like MXToolbox or by bounced mail reports from customers.

Can PHP's mail() function be abused without cPanel showing any alert?

Yes. Any script running under a cPanel account can call `mail()` and hand messages to exim directly, and cPanel does not flag this as suspicious by default since it looks identical to a normal contact form. The exim mainlog is still the reliable record, since every message still gets a `U=` entry for the account that generated it.

How do I stop a compromised WordPress site from sending spam again after cleanup?

Removing the malicious file only fixes the symptom. Rotate the WordPress admin password and any database credentials, update every plugin and the core to current versions, and search the theme and uploads folders for other PHP files that should not be executable, since a real cleanup usually finds more than one backdoor.

Put your servers on autopilot.

Connect a server in about a minute. The first week is on us.