Hacked WHM or cPanel server: what to do before cleaning any site
One account on the server is flagged — by VirusTotal, a blacklist, an ImunifyAV alert, outbound spam, or a customer complaint. The instinct is to clean that site and move on. On a shared control-panel server that instinct is how the same server gets re-flagged next month: the mechanism usually lives outside the site, in the account home, cron, the process table, or a neighbouring account. This guide covers how to tell an account compromise from a reseller or root compromise, the cPanel logs and commands to read first, and the order that contains it.
Prepared by G. Schad, WordPress and Linux security specialist
One or more accounts flagged, outbound spam, unknown cron or processes, load spikes
First question
One cPanel account, a reseller, or root?
First step
Preserve evidence and contain the account before deleting anything
Risk
Server-wide reinfection, blacklisting of the shared IP, silent data theft
What is happening
How a cPanel account compromise spreads beyond the site
On a WHM/cPanel, Plesk, or DirectAdmin server, each hosting account is a Linux user with a home directory, a crontab, the ability to run processes, and — unless isolation is configured carefully — a view of its neighbours. A compromised WordPress site gives an attacker code execution as that user. From there the interesting places are not in public_html at all: a hidden directory under ~/.config, a cron entry that re-downloads the payload, an SSH key in ~/.ssh/authorized_keys, a cPanel API token, or an outbound tunnel that keeps working after every file cleanup.
In the engagement documented in our incident report, Wordfence flagged 283 files on one WooCommerce shop, ImunifyAV agreed, and the database export was clean. All three were right about their own layer. The backdoor was a packed ELF binary in ~/.config/htop/defunct — outside the web root, invisible to every per-site tool, on a server hosting 261 accounts. Only a root-level filesystem review found it.
That is why the order of operations matters more than the cleanup itself. Clean the site first and you destroy timestamps, overwrite logs, and leave the mechanism in place.
Triage
Is it one cPanel account, a reseller, or root? How to tell
The scope of the compromise decides the response. Work out which level the attacker reached before choosing between cleaning one account and rebuilding the host.
cPanel account compromised: what changes
Most incidents stop here, and the account is still the right unit of work — but only after the sweep shows the other accounts are clean. An account compromise on a server without enforced isolation is a server finding until proven otherwise.
Reseller account hacked: what changes
A reseller can suspend, modify, and in many configurations reset passwords for the accounts it owns. Assume any account under that reseller could have been changed, and check WHM’s logs for actions taken as the reseller rather than only for malware in files.
WHM root compromised: what changes
Root can edit logs, replace binaries, and hide processes, so evidence gathered on the host is no longer fully trustworthy. Collect what you can for the record, but plan the recovery as a rebuild, not a cleanup.
Level
Indicators
What it means
Response
One cPanel account
Unexpected files, cron entries, SSH keys, or processes under a single /home/USER; the account’s own logins or API tokens you cannot explain; nothing similar in other accounts
The attacker runs code as one Linux user. Isolation decides whether that user could read or write anywhere else.
Contain and rotate that account, sweep every other account to confirm the boundary held, then rebuild the site
A reseller
Several accounts owned by the same reseller affected at once; WHM logins by the reseller from unknown addresses; accounts created, modified, or given new packages without a request
The attacker holds the reseller’s WHM credentials or a token, and can act on every account that reseller owns.
Rotate the reseller’s password, 2FA and API tokens; treat every account it owns as in scope; review what the reseller changed
Root
Unknown keys in /root/.ssh/authorized_keys; WHM root sessions from unfamiliar IPs; new root API tokens; changed packages, systemd units or timers; files in /root, /usr/local/bin or /etc you cannot account for
Every account, every log, and every tool on the host may have been altered — including the ones you would use to investigate.
Preserve what you can, then rebuild onto a fresh host and restore accounts from verified-clean sources
Signs it is the server
Signs the server is compromised, not just one site
Sign
What it usually points to
How to check
Several accounts flagged at once
Shared access, a shared vulnerability, or lateral movement — not a coincidence
List which accounts are affected and who owns them: whmapi1 listaccts want=user,owner
Outbound spam or a blacklisted IP
Something on the host is sending, whether or not any site looks infected
exim -bpc for the queue size, then the Exim checks in the spam section below
Cron entries or processes nobody recognises
Scheduled persistence or a running tool owned by a hosting user
crontab -l -u USER for each account; ps -eo user,pid,etime,args --sort=user
Load, disk, or bandwidth anomalies
Cryptominers, proxy nodes, or scanners running as an account user
ss -tnp for established outbound sessions and the process that owns each one
ImunifyAV keeps flagging the same files
A generator or scheduled task recreating what is quarantined
Compare detection times with the account’s crontab and access logs
Reinfection after a rebuild
Persistence in the account, in a neighbour, or in stolen credentials
Check SSH keys and API tokens before rebuilding again
First response
What to do first: preserve, contain, rotate, sweep
01
Preserve before you touch
Take a filesystem-level snapshot or an rsync copy of the affected account’s entire home directory (not just public_html), export the crontab, and copy the system, mail, web and cPanel logs listed in the next section. Record timestamps, owners, and hashes of anything suspicious before it is deleted or quarantined.
02
Decide the level
Use the account, reseller or root indicators above. If root is in doubt, stop treating the host as a trustworthy investigation tool and plan for a rebuild.
03
Contain the account
Suspend the cPanel account or put the site in maintenance mode, block outbound connections for that user in the firewall, kill processes owned by the user after recording them, and disable the user’s cron. Do not delete files yet.
04
Treat the account user as compromised
Rotate the cPanel password, FTP/SFTP accounts, database passwords, API tokens, and any SSH keys in the account. Check ~/.ssh/authorized_keys for keys you did not add. Assume every credential stored in the account’s wp-config.php and .env files has been read.
05
Sweep every account home, not just the flagged one
For each user: list hidden directories and recently modified files outside public_html, look for executables where none belong, check crontabs, and compare against a known-good baseline. On a multi-account server this is the step that decides whether the incident is over.
06
Check the server itself
Root and reseller WHM logins and access logs, WHM API tokens, root’s authorized_keys, systemd timers, /tmp and /dev/shm contents, listening and outbound connections, and whether CageFS, PHP handler isolation, and the malware scanner are actually enabled and enforcing.
07
Rebuild the application layer
Only now rebuild WordPress core, plugins, and themes from trusted sources, clean the database, and rotate WordPress credentials — following the same discipline as any hacked-site cleanup.
08
Close the enabling condition and verify
Patch or remove the vulnerable component, fix the isolation gap, and re-check the server after normal traffic resumes: cron, processes, outbound connections, and file changes over the following days.
Every command below only reads. Run them as root from a trusted session and save the output outside every account home. Paths are cPanel defaults on the RHEL family (AlmaLinux, CloudLinux, Rocky); verify them against your cPanel version and distribution.
What
Where
Read-only check
cPanel and WHM logins
/usr/local/cpanel/logs/login_log and session_log
grep USER /usr/local/cpanel/logs/session_log | tail -n 50 — new sessions with their source IP
Panel requests
/usr/local/cpanel/logs/access_log
grep for the account name or a suspicious IP to see what was done through cPanel, WHM, or the API
Account changes made in WHM
/var/cpanel/accounting.log
tail -n 100 /var/cpanel/accounting.log — account creation, removal, and changes, with who made them
SSH access
/var/log/secure
grep 'Accepted' /var/log/secure* — successful logins and whether they used a password or a key
Outgoing mail
/var/log/exim_mainlog
exim -bpc for the queue; the cwd= and A=dovecot_ checks in the spam section below
Web requests per domain
/var/log/apache2/domlogs/
ls -lt /var/log/apache2/domlogs/ | head, then POST requests to unexpected PHP files in the affected domain’s log
Scheduled tasks
/var/spool/cron/ and /etc/cron.d/
crontab -l -u USER for each account; ls -la --time-style=full-iso /var/spool/cron
Processes and connections
Live system
ps -eo user,pid,ppid,etime,args --sort=user and ss -tnp
Account isolation
CloudLinux CageFS
cagefsctl --list-enabled — which users are actually inside CageFS
Firewall and login failures
CSF and LFD, /var/log/lfd.log
csf -g IP to see whether and why an address is allowed or blocked
Malware detections
Imunify360 or ImunifyAV
imunify360-agent malware malicious list (Imunify360) or imunify-antivirus malware malicious list (ImunifyAV)
API tokens
WHM and each cPanel account
whmapi1 api_token_list for WHM; uapi --user=USER Tokens list for an account
Resellers and ownership
WHM
whmapi1 listresellers and whmapi1 listaccts want=user,owner
Where to look
Where to look on a hacked cPanel account: home, cron, SSH keys, processes
Figure 1 · Outside every per-site scan
Each of these needs a root-level check; a WordPress plugin runs inside one document root and reads none of them.
Hidden directories in the account home
~/.config, ~/.cache, ~/.local, and dot-directories with names that imitate legitimate tools. Executables or packed binaries here are the artefact class from our incident report — see the gsocket guide for the exact paths to check.
User crontabs and at jobs
Entries that curl or wget a URL, execute from /tmp, or run a script with a system-looking name every few minutes are the most common persistence on cPanel servers.
authorized_keys and API tokens
An SSH key or a cPanel/WHM API token survives every password rotation and every file cleanup unless it is explicitly removed.
Processes and outbound connections
A process owned by a hosting user that holds an outbound connection to an unfamiliar host — tunnels, miners, and proxies all look like this.
World-writable and temp locations
/tmp, /dev/shm, and any world-writable path are staging areas. Files there with execute bits or recent timestamps deserve attention.
Neighbouring accounts
If isolation is weak, the flagged account may be the victim of a neighbour, or the neighbour may already be the next victim. The sweep has to cover the server.
Server sending spam: finding the account behind it
A blacklisted server IP is a server symptom even when every site looks clean. Before requesting delisting, establish which of three sources is sending: a mailbox whose password was stolen, a PHP mailer planted in an account, or a legitimate form being abused. The Exim main log answers that in most cases, read-only. exim -bpc counts the queue; grep -o 'cwd=[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head lists the directories scripts sent mail from; grep -o 'A=dovecot_[a-z]*:[^ ]*' /var/log/exim_mainlog | sort | uniq -c | sort -rn | head lists the mailboxes that authenticated to send. Verify the paths against your cPanel version.
Read a sample message’s headers with exim -Mvh before deleting anything, and suspend or hold outgoing email for the one account rather than stopping mail for the whole server while you work. WHM’s Mail Delivery Reports and View Mail Statistics Summary give the same picture through the interface.
cxs, ImunifyAV, Maldet and CSF: what each one actually checks
These tools are often treated as interchangeable. They are not, and none of them is a root review. Editions and features change; check what your installed version does.
Tool
Scans files
Watches uploads or changes
Looks at processes or /tmp
Cost
ImunifyAV / ImunifyAV+
Yes — account files, on schedule or on demand
Real-time scanning and Proactive Defense are Imunify360 features
No
ImunifyAV free; AV+ and Imunify360 paid
cxs (ConfigServer eXploit Scanner)
Yes
Can hook web and FTP uploads, and watch directories
No
Commercial licence
Maldet (Linux Malware Detect)
Yes
Optional inotify monitoring of chosen paths
No
Free, open source
CSF and LFD
No — a firewall and login-failure daemon
Can alert on suspicious files in watched directories such as /tmp
The response is the same on every panel; only the locations change. Defaults shown — verify them on your installation.
What
cPanel/WHM
Plesk
DirectAdmin
Site files
/home/USER/public_html
/var/www/vhosts/DOMAIN/httpdocs
/home/USER/domains/DOMAIN/public_html
Web logs
/var/log/apache2/domlogs/
/var/www/vhosts/system/DOMAIN/logs/
/var/log/httpd/domains/
Panel logs
/usr/local/cpanel/logs/
/var/log/plesk/panel.log and the Action Log
/var/log/directadmin/
Accounts and owners
whmapi1 listaccts
plesk bin subscription --list
/usr/local/directadmin/data/users/
Mail log
/var/log/exim_mainlog
/var/log/maillog (Postfix)
/var/log/exim/mainlog
Cron per account
crontab -l -u USER
crontab -l -u SYSTEM_USER
crontab -l -u USER
For agencies and resellers
Telling client accounts what happened
When the server hosts other people’s sites, the incident has a communication side as well as a technical one. Each account owner needs to know whether their account was in scope, what was done to it, and what they must change themselves — before they hear about a blacklist or a suspension from someone else.
Tell each owner whether their account was affected, merely in scope, or cleared by the sweep — with the date the sweep ran.
Say which credentials you rotated on their behalf, and which only they can rotate: registrar, email, payment gateways, and anything stored outside the server.
Give them the window during which their data was exposed if it is known, and say plainly when it is not.
Avoid “only one site was affected” until every account has been swept. It is the sentence most often withdrawn later.
Keep a written record per account of what was found, what was changed, and what remains open — the same record an insurer or a client’s security team will ask for.
After the incident
How to secure a WHM/cPanel server after a compromise
File-integrity monitoring above the web root, covering account homes and cron, not just public_html.
Execution restrictions on home directories and temp paths; CageFS or equivalent isolation enforced for every account.
Outbound (egress) monitoring or restriction, so a tunnel or miner cannot phone home unnoticed.
Two-factor authentication, cPHulk brute-force protection, and IP restriction on WHM root and reseller logins; periodic review of API tokens and SSH keys.
WHM’s Security Advisor run after every significant change, with each warning either resolved or recorded as an accepted exception.
Heuristic ELF and binary detection left enabled in the malware scanner, with alerts routed to someone who acts on them.
A periodic root-level review of the server, independent of per-site scans — the layer this whole guide is about.
Common questions about hacked WHM and cPanel servers
How do I know if my cPanel account has been hacked?
Look for what the account did, not only for malware in its files: logins in the cPanel session log from addresses you do not recognise, cron entries you did not create, SSH keys or API tokens you did not add, unexpected files outside public_html, and outgoing mail you did not send. Any one of these on an account you administer is enough to treat it as compromised.
Is a hacked cPanel account the same as a hacked server?
No. A hacked account means an attacker runs code as one Linux user; a hacked server means they reached root or a reseller. The difference is whether isolation held. Until every other account has been swept and the root indicators checked, treat it as an open question rather than assuming the smaller answer.
Should I suspend the cPanel account or take the whole server offline?
Usually suspend the account and block its outbound connections, which stops harm without stopping every other customer. Take the server offline, or plan an immediate rebuild, when root compromise is likely: unknown root keys, unexplained WHM root sessions, or changed system binaries and services.
Which cPanel log files show how the attacker got in?
Start with /usr/local/cpanel/logs/session_log and login_log for panel logins, /usr/local/cpanel/logs/access_log for what was done through cPanel and WHM, /var/log/secure for SSH, the domain logs under /var/log/apache2/domlogs/ for web requests to the site, and /var/cpanel/accounting.log for account changes. On shared hosting the entry point is often older than the retained logs, so copy them before they rotate.
Does CageFS stop one account from infecting another?
It limits what an account can see of the filesystem and other users, which blocks many cross-account paths — when it is enabled for that account. Check with cagefsctl --list-enabled rather than assuming. CageFS does not protect against stolen credentials, a compromised reseller, or root.
Is cxs or ImunifyAV better for a cPanel server?
They overlap on file scanning and differ in how they are licensed, how they watch uploads, and how they clean. Either is better than none, and neither replaces a root review: neither examines SSH keys, API tokens, reseller actions, or whether isolation holds.
The server IP is blacklisted for spam. How do I find which account is sending?
Read the Exim main log. Counting the cwd= values shows which account directories handed mail to Exim, and counting A=dovecot_ entries shows which mailboxes authenticated to send. Close the source first; delisting before that only buys a few hours.
Can a compromised reseller account reach the other resellers’ accounts?
Not through WHM itself: a reseller acts on the accounts it owns. It can still reach further if the server’s isolation is weak, if credentials are reused across resellers, or if the attacker escalates to root from one of its accounts. Sweep beyond the reseller’s own accounts before concluding.
My host says only one account is infected. Can I just clean that one?
You can clean it, but you cannot conclude the incident is over from that statement alone. Ask the host what they checked: a per-account malware scan does not cover cron, processes, hidden home-directory files, or neighbouring accounts. If you administer the server, sweep it yourself or have it reviewed at root level.
Wordfence and ImunifyAV are both clean now. Is the server clean?
They are clean about their own layers — WordPress files and the files ImunifyAV is configured to scan. Neither examines the process table, user crontabs, SSH keys, API tokens, or a packed binary in a hidden dot-directory. The documented WHM incident is exactly this case.
Should I reinstall the whole server?
Sometimes. If root access is suspected, if isolation was never configured, or if the number of accounts makes a reliable sweep impractical, a rebuild onto a fresh host with accounts restored from verified-clean application sources is the safer path. A contained single-account compromise with intact root controls usually does not need it.
Can you do this for a server I manage for clients?
Yes. Agencies and resellers are the most common case. The work is scoped as a server incident with per-account findings, ownership of client communication and per-site cleanup is agreed up front, and the report separates server findings from per-account actions.