A critical authentication bypass in cPanel & WHM gave attackers root access to over a million publicly exposed servers — silently, without a password, defeating two-factor authentication — for sixty-four days before anyone patched a thing.
What Was Actually at Stake
cPanel and WHM are not just web applications. They are the administrative nervous system of shared hosting. WHM — Web Host Manager — is the root-level interface through which a hosting provider manages every customer on a machine: SSL certificates, DNS zones, email, databases, resource quotas, the lot. cPanel sits one level below it as the individual customer portal. Together they manage, depending on the source, somewhere north of 70 million domains worldwide.
A Rapid7 Shodan scan conducted around the time of disclosure found approximately 1.5 million cPanel instances directly reachable from the open internet. Every single one running a version newer than 11.40 — which is old enough that virtually every active installation qualifies — was fully affected by CVE-2026-41940. This is not hyperbole. The cPanel advisory itself confirmed the vulnerability affects all currently supported release tracks without exception.
The CVSS score assigned was 9.8 out of 10. The impact, when you think through what WHM access actually means, is arguably worse than that number suggests.
The Mechanism: A Session File Injection Nobody Was Watching
To understand what happened here, you need to understand how cPanel manages authenticated state.
When a user attempts to log in — even with wrong credentials — cpsrvd, the cPanel service daemon, does not simply reject the request and discard it. Before it ever validates a password, it creates a pre-authentication session file on disk at /var/cpanel/sessions/raw/. This file is a flat key-value store, one property per line:
local_ip_address=172.17.0.2
needs_auth=1
tfa_verified=0
ip_address=172.17.0.1
Session files are cPanel’s state machine across connections. A successful login later upgrades the same pre-auth file by writing user= and pass= into it. The on-disk structure is intentionally human-readable and line-delimited — which is precisely where the problem begins.
The vulnerability is a CRLF injection. \r\n — carriage return and line feed — are the two invisible characters that signal a new line. In a flat key-value file where each line is a separate session property, injecting \r\n inside a value means injecting a new property. If an attacker can get those characters written into the session file, they can fabricate session state wholesale.
cPanel had already written a function to prevent exactly this: filter_sessiondata, which strips \r\n, =, \, and , from all session values before they reach disk. The function existed. It was tested. It worked. It just was not being called from inside saveSession — the function that actually writes session files. Every call site was supposed to invoke the sanitizer first. One code path in cpsrvd, handling HTTP Basic authentication headers, never did.
The patch, when it eventually arrived, was essentially this: move the filter_sessiondata call into saveSession so it fires regardless of which caller reaches it. That was it. A function relocation. The total time to write and ship the patch after the advisory went public was two to three hours.
How the Exploit Works End-to-End
The attack chain is elegant in the way that the most damaging exploits tend to be — a small number of individually unremarkable steps that combine into something catastrophic.
Step 1 — Mint a pre-auth session. The attacker sends a deliberately failed login:
Host: target:2087
Content-Type: application/x-www-form-urlencoded
user=root&pass=wrong
cpsrvd returns a 401 and issues a session cookie:
Set-Cookie: whostmgrsession=:Wg_mjzgt1hyfXefK,1bd3d4bf5ecbf83b660789ab0f3198fa
That cookie contains two parts separated by a comma: the session name, and a per-session encryption secret called ob. The ob value is what cpsrvd uses to symmetrically encode the pass field before writing it to disk — so raw passwords never sit in plaintext session files.
Step 2 — Strip the encryption key. The attacker sends the next request using only the base session name, without the ,<ob> portion of the cookie. When ob is absent, the encoder check fails silently:
my $encoder = $ob && Cpanel::Session::Encoder->new( 'secret' => $ob );
If $ob is empty, $encoder evaluates as falsy, encoding is skipped entirely, and whatever is in $pass lands on disk verbatim. No encoding. No sanitization. Raw bytes.
Step 3 — Inject fabricated session properties. The attacker sends an HTTP Basic Authorization header whose base64-decoded <user>:<pass> field contains \r\n-separated fake session keys in the password value
With no sanitizer running and no encoder firing, cpsrvd writes this directly to the raw session file. The result on disk:
pass=x
hasroot=1
tfa_verified=1
user=root
cp_security_token=/cpsess9999999
successful_internal_auth_with_timestamp=1777462149
Step 4 — Flush the JSON cache. cpsrvd does not read the raw text file on subsequent requests. It reads a parallel binary cache at /var/cpanel/sessions/cache/, which is a JSON-serialized snapshot of the session hash. Because JSON encodes \r\n as escape sequences rather than actual newlines, the injected properties sit trapped inside the pass string — invisible as separate keys. The attacker needs to force cpsrvd to re-parse the raw file and rebuild the cache from it.
This is achieved by sending a request to any URL without a valid security token. The do_token_denied handler in cpsrvd invokes Cpanel::Session::Modify::new — which reads the raw file with nocache => 1, bypassing the JSON — and then Cpanel::Session::Modify::save, which writes both the raw file and the JSON cache back from the parsed hash. The injection is now promoted to top-level keys in the cache JSON.
Step 5 — Full root access, no password checked. On every subsequent request, cpsrvd loads the session, sees successful_internal_auth_with_timestamp set, and the password validation block in docheckpass_whostmgrd short-circuits completely:
if ($successful_internal_auth_with_timestamp or $successful_external_auth_with_timestamp) {
return $Cpanel::Server::AUTH_OK, 0; # /etc/shadow never consulted
}
The attacker has a fully authenticated root WHM session. Two-factor authentication was bypassed because tfa_verified=1 was injected directly into session state. No password was ever verified. No real credential was needed.
64 Days: What That Window Actually Means
The first confirmed exploitation attempts were logged on February 23, 2026. KnownHost CEO Daniel Pearson stated publicly that his company had seen execution attempts as early as that date and that the vulnerability had been used in the wild for at least 30 days before any disclosure. The public advisory came on April 28, 2026. The vulnerability was formally assigned CVE-2026-41940 the following day.
Webhosting.today reported that the vulnerability had been flagged to cPanel roughly two weeks before that date, and that cPanel’s initial response was that nothing was wrong.
Sixty-four days of zero-day exploitation on the management plane of a significant fraction of the internet’s hosting infrastructure. During that entire window, there was no patch to apply, no CVE to search for, no advisory to act on. The attacks were invisible to every scanner, every IDS signature, every vulnerability management tool in existence — because the vulnerability was not public knowledge.
This is the nature of pre-disclosure exploitation: the attackers know, the defenders do not, and the gap between those two states is where the real damage happens.
The Invisible Backdoor Problem
Root access to a WHM server via an authentication bypass is not a crime that announces itself. An attacker operating during those 64 days had every reason to be quiet.
What can an attacker do with a forged WHM session?
Create legitimate-looking accounts. WHM allows the creation of reseller and cPanel accounts with full hosting privileges. A backdoor account created during the exploitation window looks identical to any other hosting account in the system. It survives a password change on the root system user. It survives the patch. It potentially survives a log review if the reviewer does not know what timeframe to look in.
Install persistent server-level malware. With root access, an attacker can drop anything anywhere: a reverse shell in a cron job, a modified SSH daemon, a rootkit in a kernel module, a web-accessible backdoor in a globally included PHP configuration. These persist through control panel updates because they live at the OS level, not inside cPanel’s own file tree.
Harvest every credential on the machine. cPanel stores database passwords, email account credentials, FTP passwords, and API tokens — for every hosting customer on the server. A single compromised WHM instance is not a single compromised website. It is a full credential dump for potentially dozens or hundreds of customers, all of whose downstream systems are now at risk regardless of whether those customers ever patched anything themselves.
Manipulate DNS silently. WHM controls DNS zones. An attacker can redirect mail delivery, redirect domain traffic, or insert DNS records pointing subdomains to infrastructure they control — for any customer on the machine. This can be used for phishing, for credential harvesting, or for establishing persistent footholds in customer environments by hijacking their own DNS.
Access email at the server level. Every email account on every hosted domain passes through infrastructure the attacker now controls. Email archives can be read, forwarded, or deleted. Password reset flows for third-party services tied to those email addresses are trivially interceptable.
Steal TLS private keys. SSL certificates and their private keys for all hosted domains are stored on the server. With those keys and a redirected DNS record, an attacker can perform transparent man-in-the-middle attacks on any of those domains’ HTTPS traffic.
None of these actions require any further exploitation. They are routine administrative operations that happen to be destructive when performed by an unauthorized party with a forged session.
The Scale of Confirmed Exposure
Within hours of the advisory going public, Namecheap, KnownHost, HostPapa, InMotion, and hosting.com all blocked access to cPanel and WHM ports across their own infrastructure. They locked their own customers out of their own control panels because the alternative was watching the entire customer base get compromised in real time.
That decision — to deliberately cut off legitimate customer access to self-service management tools — is not made lightly by any hosting provider. It is a last resort. The fact that major providers made it within hours of the advisory signals how seriously the technical staff at those companies assessed the immediate exploitation risk once the details were public.
On April 29, watchTowr published a full technical breakdown of the vulnerability along with a working proof-of-concept exploit. With a public exploit available and automated detection templates already built around it, the gap between disclosure and mass exploitation has closed. Anyone with a Shodan query and the PoC can scan and hit 1.5 million exposed instances.
The PoC is public. The vulnerable population is Shodan-queryable. The exploit requires no authentication, no credentials, no prior access, and no specialized knowledge beyond the ability to send an HTTP request. Automation of this is not theoretical.
Servers That Were Patched Are Not Necessarily Clean
This is perhaps the most uncomfortable truth of the CVE-2026-41940 situation: patching closes the vulnerability. It does not undo anything that happened during the window.
A server that was running an unpatched cPanel installation between February 23 and April 28 was reachable by anyone who knew about this vulnerability. Whether any particular server was actually targeted during that window depends on factors no patch can retroactively determine.
The problem with a forged session attack is that its artifacts are specifically designed to look legitimate. Session files are transient by nature — they are created, used, and cleaned up constantly. A session created via this exploit and used briefly looks almost identical to a normal session in any reasonable log review. A backdoor account created through a forged WHM session is indistinguishable from an account a legitimate administrator created.
The 64-day window was long enough for thorough, patient attackers to establish persistence that outlasts both the patch and any first-pass forensic review of the obvious indicators.
A Function That Was Always There
The piece of this story that sits uncomfortably is how close the fix was to the problem all along.
filter_sessiondata — the function that strips CRLF characters from session data — was not missing from the codebase. It was not unwritten. It was not a new security control that needed to be designed, reviewed, and implemented. It existed. It worked. It had been in place for years. The entire exploit chain, all five steps of it, leading to unauthenticated root access across more than a million internet-exposed servers, ultimately rests on that function not being called from inside saveSession.
The patch took 2 to 3 hours to write and ship after the advisory went out. The exploitation window was 64 days. That window opened the day a researcher reported the issue to cPanel and got back the response that nothing was wrong. I cannot make this BOLD enough. “nothing is wrong”. Period.
That is the cost of a missed function call: 64 days of unrestricted access to the management plane of millions of websites, an unknown number of compromised servers with persistence that survived the patch, and a credential exposure footprint that extends far beyond any server that was directly hit.
Sources: watchTowr Labs (Sina Kheirkhah) · HackingPassion.com · cPanel Official Advisory