CVE-2026-41940 cPanel Exploitation From a Honeypot Perspective
CVE-2026-41940 cPanel Exploitation From a Honeypot Perspective
cPanel released an emergency patch on April 28th, 2026 for CVE-2026-41940, an unauthenticated remote authentication bypass affecting every supported version of cPanel & WHM after 11.40 - somewhere a bit south of 1 million internet-facing instances seem to be online. Technical writeups and proof-of-concepts appeared the following day. By the time the patch dropped, the bug had already been exploited as a zero-day for months; KnownHost has reported in-the-wild activity dating back to late February.
We aren’t going to rehash the root cause - technical blogs like watchTowr’s research cover it well. What we are going to do is walk through what’s hitting our cPanel honeypots in the days following public disclosure.
Key Takeaway: Within a couple days after patch release, our cPanel decoys logged 340 attacks across eight distinct payload variants. The exploitation pattern decomposes into three stages - minting a forged session, riding the cache-propagation race, and issuing privileged json-api calls. The operators we’ve tracked through the third stage split cleanly along intent: recon, RCE validation, SSH key persistence, and outright account takeover. None of them are subtle, and any one of them ends with an attacker holding root on the host.
The Vulnerability
CVE-2026-41940 is a CVSS 9.8 pre-authentication bypass in cpsrvd, the
cPanel service daemon. The exploit chains two flaws. A malformed
whostmgrsession cookie - the base session name without its trailing
encryption secret - tricks cpsrvd into skipping the per-session
encryption that normally protects the pass field on disk. With
encryption out of the way, raw \r\n characters in a Basic Auth
password inject straight into the session file as separate top-level
records. The two that matter are user=root and
successful_internal_auth_with_timestamp=…; the latter is a magic flag
that tells cpsrvd’s auth handler to skip credential validation
entirely on every subsequent request.
There’s a catch. cpsrvd keeps every session as both a flat key=value
text file and a JSON cache, and the loader reads the cache first.
Because JSON serialises the embedded \r\n bytes back into the pass
string, the injected lines exist as separate records in the raw file
but stay buried inside pass in the cache - invisible to the loader.
The exploit closes that gap with a follow-up request to a session-aware
endpoint sent with a missing or wrong security token. That triggers
cpsrvd’s token-denied path, which forcibly re-reads the raw file
(cache-bypassed), parses the injected lines as proper top-level fields,
and rewrites both files. From the next request onwards the cache
contains the injection at top level, and cpsrvd waves the attacker
through as root.
The immediate consequence is full administrative access to WHM. On a shared hosting box, that’s root-equivalent control over the host and every customer account it serves.
What We’re Seeing
Our cPanel honeypots logged 340 attacks in the most recent 48-hour window across eight distinct request shapes. Collapsed across decoy instances, the distribution looks like this:
| Count | Request |
|---|---|
| 284× | POST /login/?login_only=1 (Basic Auth + form body) |
| 25× | GET /scripts2/listaccts |
| 14× | GET /cpsess{id}/json-api/version |
| 7× | GET /cpsess{id}/json-api/listaccts |
| 4× | GET /json-api/authorizesshkey |
| 3× | GET /json-api/listaccts (Basic Auth) |
| 2× | GET /login/?login_only=1 |
| 1× | GET /cpsess{id}/json-api/passwd |
The volume distribution is informative on its own. The mint step (POST /login/) outnumbers everything else combined - operators are spraying minted sessions broadly - possibly used as a recon step to assess vulnerability before firing a full exploit. The post-exploitation endpoints that follow are where the actual operator intent is visible.
The Three-Stage Pattern
Defused tags this activity with three labels, each mapping to a stage in the chain.
Preauth Session Mint. The initial POST /login/?login_only=1 carrying a malformed whostmgrsession cookie and a CRLF payload in the Basic Auth header. This is where the session file is written with attacker-controlled fields.
Cache Propagation Gadget. Activity inside the race window - when the injected fields exist in cpsrvd’s JSON session cache but haven’t yet been overwritten by the canonical session writer. The operator needs to land their next request before that overwrite happens.
Authenticated json-api Call. The payoff - any privileged API call carrying the forged cpsess{id} path or whostmgrsession cookie. From here, the attacker is operating as root.
Tagging the stages separately matters because the first two are nearly invisible from logs alone. A 401 on /login/ looks like a typo. The interesting telemetry is in stage three - what the operator does once they’re trusted.
Behavioural Profiles
Across the IPs we tracked through stage three, four distinct behavioural profiles emerged.
Heavy Recon, Then RCE
The highest-volume profile - seventeen requests over fifteen hours -
centred on session validation followed by an RCE check. The operator
repeatedly minted fresh session IDs and probed /json-api/version
against each, consistent with verifying a pool of forged sessions
before committing to anything noisier on the server side.
Once a working session was confirmed, the chain pivoted:
GET /cpsess7280227513/json-api/listaccts?api.version=1
GET /cpsess7280227513/json-api/system?api.version=1&command=id The system endpoint with command=id is the textbook post-bypass
RCE check - running id to confirm the executing user. It’s exactly
what you’d expect from an operator validating a fresh capability
before deciding what to do with it next. The User-Agent across all
seventeen requests was a stock Chrome string.
SSH Key Persistence
A tighter, more deliberate pattern - seven requests in a forty-minute
window, all curl/7.74.0, and all carrying a Basic Auth header
rather than a forged cpsess cookie. The decoded credential pair
was root:H2ckt3ch@g0dl1k3, suggesting the operator either harvested
a working credential elsewhere or ran a credential spray decoupled
from the CRLF chain.
The interesting part is what they did with the access:
GET /json-api/listaccts
GET /json-api/authorizesshkey?api.version=1&authorize=1&text=ssh-rsa+AAAA... The authorizesshkey endpoint adds an arbitrary public key to the
target account’s authorized_keys. Once that’s in place, the SSH
layer doesn’t care about cPanel anymore - the operator has a
persistent, credential-independent way back into the host. It’s the
kind of foothold that survives patching, password rotations, and
most incident response playbooks short of a full re-image.
The implanted key is a 4096-bit RSA key. SHA256 fingerprint
rRsuHSATsKKFkpcxsXD8xqGmLwN55NiIMDWpszH4Mcc. If you’re triaging a
possibly-compromised cPanel host, that authorized_keys file is the
first place to look.
Account Takeover
A single request, sent at the very start of the window:
GET /cpsess5557513169/json-api/passwd?api.version=1&user=root&password=goliathstress A direct passwd call against the root account, attempting to reset
the password to goliathstress. One shot, python-requests/2.25.1,
then gone. This profile reads as either smash-and-grab automation or
an opportunistic test - change the password, log in normally
afterwards, no exploit chain needed for follow-up access.
Reconnaissance Only
Four requests inside a single second - version and applist
against two separate forged session IDs - then nothing. No
follow-on, no listaccts, no privileged calls. This profile looks
like coverage scanning: confirm the bug works, log the host, move on.
Exploit Volume is High, and Patching is Half the Story
Our cPanel honeypot footprint covers a tiny fraction of the ~850k internet-facing cPanel instances out there. Inside 48 hours it picked up four distinct stage-three operators. That hit density means broad, deliberate scanning across most of the routable internet - not the slow ramp-up of a fresh CVE entering the ecosystem, but high-velocity exploitation already in full swing.
With a public PoC out and a CISA KEV listing within a day of disclosure, the operational severity here is hard to overstate. Hosting providers that pre-emptively blocked TCP/2087 ahead of patching spared themselves the worst of it; everyone else needs to assume their session directories should be triaged regardless of what shows up in access logs.
Obvious, but worth stating - SSH
key persistence, account modifications and such outlive the cPanel patch entirely - patching
cpsrvd doesn’t remove the ssh key for example, and the key continues working
whether cPanel is running or not.
If you’re patched but didn’t
audit authorized_keys on every account, you may still be hosting
an operator’s foothold.
What To Look For
Treat any of the following as evidence of attempted exploitation, regardless of HTTP status:
POST /login/?login_only=1with a malformedwhostmgrsessioncookie - typically a leading colon or a missing encrypted segment- Basic Auth headers containing raw or URL-encoded
\r\nsequences - Any
/cpsess{id}/json-api/systemrequest with acommand=parameter /json-api/authorizesshkeyrequests carryingauthorize=1and atext=ssh-...payload/json-api/passwdcalls altering therootaccount- Bursts of
/json-api/versionprobes across many distinctcpsessIDs from the same source
On the host side: review /var/cpanel/sessions/raw/ for sessions you can’t account for, audit every account’s authorized_keys, and check /var/log/secure for SSH logins immediately following any of the above.
High-Fidelity Indicators of Compromise
Network IOCs - Source IPs
| IP Address | Behaviour | First Seen (UTC) | Last Seen (UTC) |
|---|---|---|---|
103.98.152.18 | Recon + RCE (system?command=id) | 2026-05-01 14:46 | 2026-05-02 05:34 |
80.87.206.131 | SSH key implant (authorizesshkey) | 2026-05-01 06:17 | 2026-05-01 06:58 |
176.65.132.199 | Recon (version, applist) | 2026-05-01 19:48 | 2026-05-01 19:48 |
176.65.148.253 | Account takeover (passwd) | 2026-04-30 19:44 | 2026-04-30 19:44 |
More IOCs available in Defused telemetry.
Implanted SSH Key
| Field | Value |
|---|---|
| Type | ssh-rsa (4096-bit) |
| SHA256 | rRsuHSATsKKFkpcxsXD8xqGmLwN55NiIMDWpszH4Mcc |
| MD5 | d6:e5:04:4c:c8:d5:46:69:1b:1f:e1:ce:3c:b7:83:fb |
Credential Spray Pair
root:H2ckt3ch@g0dl1k3 Base64 form (as seen in Authorization: Basic headers): cm9vdDpIMmNrdDNjaEBnMGRsMWsz
Patch and Hunt
Patch first - cPanel & WHM 11.136.0.5, or whichever fix lands on your release branch - then restart cpsrvd. After that, hunt. Pull access logs for the last sixty days and grep for the indicators above; with confirmed in-the-wild activity going back to late February, a freshly-patched host is not necessarily a clean host. Audit every account’s authorized SSH keys, rotate WHM root and reseller credentials, and review your session directory for files you can’t trace to a real login.
The exploit gets you root in one HTTP request. The implant lasts until you remove it. Patch and check.
Parts of the writeup above have been AI-assisted.