Bali, Indonesia
Insights

Restoring a Hacked WHM Server? Pick a Backup Taken Before the Breach

October 31, 2026
0:00
When a WHM server has been taken over through an authentication bypass, the first instinct is to grab the most recent backup and restore it. It feels like the fastest way back to normal, but the newest backup is often the one most likely to contain the problem. If the attacker had root for days before anyone noticed, every backup taken in that window faithfully preserved their web shells, extra accounts, and SSH keys. The real question is not which backup is newest, but which backup was taken before the first malicious login. The sections below follow that decision the way a post-mortem would: what the damage looks like, how to work backward through the logs, the point where the restore plan usually changes, what to do in the meantime, and what to change so the next incident leaves you a clean option.
The recent cPanel & WHM advisories show why this matters. According to the advisory details, a missing input-sanitisation step in a secondary code path that handles Basic authentication and session generation lets an unauthenticated attacker use CRLF (carriage return and line feed characters) injection to forge an administrative session. It affects versions after v11.40 and is rated CVSS 9.8. From a forged session, WHM API features give root-level control and remote code execution. A forged session is not a password guess. There is no failed-login storm for cPHulk to block, and the attacker never needs to know the root password. What they do with that session is what you end up cleaning: creating a reseller or cPanel account, adding an API token, dropping a PHP file into some public_html, adding a cron job, or putting a key in /root/.ssh/authorized_keys. The symptom that gets noticed is rarely the login itself. It is usually spam leaving Exim, a redirect on a customer site, or an unfamiliar account in the WHM list. By then the initial access may be well in the past. Restoring last night's backup clears the visible symptom for a while, and then the same symptom comes back, because the restore also brought back whatever caused it.
The investigation is really about one timestamp: the earliest moment you can show the attacker had access. Discovery time does not count. The restore point has to be older than the first malicious action, ideally with some margin. Start with cPanel's own logs, which on a standard install live under /usr/local/cpanel/logs/. The access_log file records requests handled by cpsrvd, the cPanel service daemon, including WHM traffic. The session_log file records sessions being created and ended, and login_log records logins. Look for root or reseller sessions from IP addresses your team does not use, and for WHM API calls that create accounts, change passwords, or manage tokens. Those API calls typically show up as json-api paths behind a /cpsess token in the URL.
BASH
# Session records mentioning root (line format varies by cPanel version)
grep 'root' /usr/local/cpanel/logs/session_log | less

# WHM API calls: scan for account creation, password or token changes
grep 'json-api' /usr/local/cpanel/logs/access_log | less

# Successful SSH logins: /var/log/secure on RHEL-based systems,
# /var/log/auth.log on Debian and Ubuntu
grep 'Accepted' /var/log/secure | less
Then pivot from the artifacts you already know about. For each thing that should not exist, such as a strange account in /var/cpanel/users/, an API token nobody recognizes in WHM's API token management page, a web shell, or an odd cron entry, note when it appeared. File modification times can be faked with touch, so treat them as a hint rather than proof. Inode change time (ctime, shown by stat) is harder to fake from normal tools, but it also changes when files are copied or restored, so it is only meaningful on the original disk. Two things catch people out here. Logs rotate, so if the oldest log you still have covers only recent weeks, your earliest finding is a lower bound and the breach may be older than the logs can show. And an attacker with root can edit logs. Gaps in otherwise continuous logs, or a log that starts suspiciously recently, are evidence in their own right.
This is where the restore plan typically changes. Once you have an earliest-evidence timestamp, put your backup dates next to it.
BASH
# Default destination is often /backup; confirm in WHM Backup Configuration
ls -l --time-style=long-iso /backup/

# List a compressed account archive without extracting or restoring it
tar -tvzf /backup/YYYY-MM-DD/accounts/USERNAME.tar.gz | grep 'public_html' | grep '[.]php$' | less
The backup date tells you when the backup ran, which is also the moment its contents were captured. If that date is later than your earliest evidence, assume the backup is contaminated, even if it looks fine. Listing the archive lets you check whether a known web shell filename or a malicious cron file is already inside. Finding one confirms the backup is dirty. Not finding one does not prove it is clean, because you only know about the artifacts you have discovered so far. It also helps to be clear about what a backup actually contains. A cPanel account backup carries that account's home directory, databases, mail, and account settings, so restoring it brings back that user's web shells and malicious cron jobs. It does not cover the whole server. Server-level changes like root SSH keys, altered system binaries, extra WHM API tokens, or new resellers are not removed by restoring accounts onto the same machine. If the system was rooted, the safer route is usually a freshly built and patched server, with accounts restored onto it from a pre-breach point. Even a pre-breach restore needs a site-level review afterwards, because some changes are easy to miss in an archive listing. Injected rewrite rules are a common example, covered in Auditing .htaccess Files for Injected Redirects After a cPanel Server Compromise. The cost of an older restore point is data. Everything created between the backup and today, such as orders, posts, and mail, is missing. That gap is usually filled by exporting specific newer data from the compromised server, a database table or a mailbox folder for example, reviewing it, and importing it on the clean server. Keep that selective. Copying a whole newer home directory across defeats the point of choosing an older backup. From a support desk point of view, this is the part that most often confuses site owners. They hear that a backup exists from yesterday and do not understand why anyone would restore one from weeks ago. Explaining the earliest-evidence timestamp, and showing them the log line, usually settles it.
Working out the right restore point can take hours, and the compromised server is often still serving traffic. In that window, do these in order:
  1. Copy logs, and a snapshot of the server if your platform allows it, to another system before changing anything. Cleanup destroys evidence you may still need.
  2. Restrict WHM and cPanel ports (2087 and 2086 for WHM, 2083 and 2082 for cPanel by default) to known admin IPs. The trade-offs are covered in Should You Restrict WHM Ports with Host Access Control or a Firewall?.
  3. Update cPanel & WHM to a build that the vendor advisory lists as fixed, then confirm the installed version instead of assuming the update ran.
  4. Rotate the root password, revoke API tokens you do not recognize, remove unknown SSH keys, and end active WHM sessions.
  5. Suspend accounts the attacker created rather than deleting them, so they remain available as evidence.
These steps limit further damage. They do not make the server trustworthy again. Treat the machine as a source of evidence and selected data, not as the restore target.
The worst version of this incident is the one where every backup is newer than the breach. That tends to happen in two situations: retention is short, with only a handful of daily copies, or backups live on the same server, where an attacker with root can delete or alter them. Retention is the first lever. WHM's backup configuration lets you keep daily, weekly, and monthly copies separately. How far back you need to reach depends on how quickly you would realistically notice a compromise, and for a silent session forgery that can be longer than people expect. Location is the second. Store backups somewhere the server's own root account cannot overwrite or remove, such as a remote destination with credentials that can write but not delete, or object storage with versioning or object lock enabled. If root on the WHM box can remove the backups, so can whoever has taken over root. Logs are the third. The investigation above only reaches as far back as your logs do. Sending cpsrvd, SSH, and web server logs to a separate log host keeps them safe from both rotation and tampering, and it means the earliest-evidence timestamp is something you can actually find. Finally, test restores on an isolated server now and then. It is the only reliable way to know the archives are usable and how long a rebuild really takes. If you take one habit from this: before restoring a compromised WHM server, write down the earliest timestamp you can prove the attacker had access, and only consider backups older than that. Restore onto a clean, patched server, bring newer data across selectively, and then fix retention, backup location, and log storage so the next time you need an older restore point, one actually exists.