The Internet Is Falling Down, Falling Down, Falling Down (cPanel & WHM Authentication Bypass CVE-2026-41940)
cPanel & WHM authentication bypass CVE-2026-41940 exploited in-the-wild affecting all supported versions.
Summary
CVE-2026-41940 is a critical authentication bypass vulnerability in cPanel & WHM's session handling that affects all currently supported versions and has been actively exploited as a zero-day. The flaw stems from improper session data filtering and encoding, allowing attackers to manipulate session files through CRLF injection. watchToyr Labs published technical analysis and coordinated rapid mitigation, with patched versions released across multiple release tracks (110.0.x through 136.0.x).
Full text
Hello! Yes, it's all a disaster again! Let's get this party started: 0:00 /0:12 1× No comments today, so imagine this:We wrote something that we find very funny,Nobody else gets it,But everyone humors us Just like a typical watchTowr Labs blog introduction.As with all watchTowr Labs research, this didn't start with a blog post - but is the end result of a coordinated capability that enables watchTowr clients to rapidly react to, and autonomously mitigate, emerging threats.AI-Driven Rapid Reaction executed across the watchTowr client base, leveraging watchTowr research to identify affected instances and validate exposure rapidly after disclosure,Active Defense mitigation rules were released, enabling autonomous mitigation at the network edge.When exploitation happens in hours, watchTowr delivers what no one else can: time to respond.What Is cPanel & WHM?Well, dear reader - for those that have never had the joyous experience of managing shared hosting infrastructure, cPanel and WHM is the control panel solution that runs, depending on who you ask, somewhere north of 70 million domains. WHM is the administrative interface - root-level access to the server, SSL certificates, security protocols, the lot - and cPanel is the user-facing panel for individual hosting accounts. Think of it as the keys to the kingdom, and then the keys to every individual apartment inside the kingdom. If the kingdom was the Internet and the apartments were websites. For everything.What Is CVE-2026-41940 And Why Is It So Catchy?According to cPanel, this vulnerability affects - and we cannot stress this enough - all currently supported versions of cPanel & WHM. Not some, or a few, or a specific release track. cPanel have been fairly eco-friendly, producing an advisory that used few word to ensure few paper print.What we do know, though, is that this is a vulnerability affecting "session loading and saving" - or in plainer non-cPanelican English, an "Authentication Bypass"And then it got worse, with KnownHost confirming in-the-wild exploitation has been ongoing and that this vulnerability was used as a zero-day against - as we mentioned - the management plane of a significant part of the Internet.cPanel, in their many words, recommends upgrading to the following patched versions (ideally yesterday?):cPanel & WHM 110.0.x - patched in 11.110.0.97 (was 11.110.0.96)cPanel & WHM 118.0.x - patched in 11.118.0.63 (was 11.118.0.61)cPanel & WHM 126.0.x - patched in 11.126.0.54 (was 11.126.0.53)cPanel & WHM 132.0.x - patched in 11.132.0.29 (was 11.132.0.27)cPanel & WHM 134.0.x - patched in 11.134.0.20 (was 11.134.0.19)cPanel & WHM 136.0.x - patched in 11.136.0.5 (was 11.136.0.4)For avoidance of doubt, for today's schenanigans, we reviewed:cPanel & WHM 11.110.0.97 (patched)cPanel & WHM 11.110.0.96 (unpatched)As always, with clues from the ether and drama in our heads, we pulled the pin out of the proverbial grenade and jumped on it.Let's Get On With It - It's Time To (Be) DiffIgnoring the pain of our proverbial explosion, we identified 3 modified files of interest:Cpanel/Session.pm (saver) Cpanel/Session/Load.pm (loader) Cpanel/Session/Encoder.pm (new hex round-trip primitives)However, specifically the changes to the function saveSession in Session.pm caught our eye:If you zoom in on your screen (bring it closer to your face), we're greeted with this beautiful hint:Being a bit more scientific, we see the following actual code changes:sub saveSession { my ( $session, $session_ref, %options ) = @_; ... my $ob = get_ob_part( \$session ); return 0 if !is_valid_session_name($session); - my $encoder = $ob && Cpanel::Session::Encoder->new( 'secret' => $ob ); - local $session_ref->{'pass'} = $encoder->encode_data( $session_ref->{'pass'} ) - if $encoder && length $session_ref->{'pass'}; + filter_sessiondata($session_ref); # <-- NEW + if ( length $session_ref->{'pass'} ) { + if ( defined $ob && length $ob ) { + my $encoder = Cpanel::Session::Encoder->new( 'secret' => $ob ); + $session_ref->{'pass'} = $encoder->encode_data( $session_ref->{'pass'} ); + } + else { + $session_ref->{'pass'} = # <-- NEW + 'no-ob:' . Cpanel::Session::Encoder->hex_encode_only( $session_ref->{'pass'} ); + } + } ... } The filter_sessiondata function leveraged above in Session.pm already exists though, albeit with a new call, and has a simple task (as always in security): sanitize \r\n=\ from existing in any input/fields that are passed.sub filter_sessiondata { my ($session_ref) = @_; no warnings 'uninitialized'; ## no critic(ProhibitNoWarnings) # Prevent manipulation of other entries in session file tr{\r\n=\,}{}d for values %{ $session_ref->{'origin'} }; # Prevent manipulation of other entries in session file tr{\r\n}{}d for @{$session_ref}{ grep { $_ ne 'origin' } keys %{$session_ref} }; # Cleanup possible directory traversal ( A valid 'pass' may have these chars ) tr{/}{}d for @{$session_ref}{ grep { exists $session_ref->{$_} } qw(user login_theme theme lang) }; return $session_ref; } For example, if a caller of this function provides the following value:pass = foo\nhasroot=1 filter_sessiondata will do its thing and massacre any value into becoming:pass = foohasroot=1 This lines up with what we'd roughly expect for a basic protection against CRLF.But, the bigger question - if filter_sessiondata already existed, what is the patch doing?It's "simple" - the patch moves the filter_sessiondata call inside saveSession itself, rather than relying on every caller to remember it. The patch also introduces another change we'll circle back to shortly - but first, something more exciting. Let's look at how session files are structured in cPanel and WHM.Anatomy Of A Session FileWe have a hunch session files are related, given the constant harassment by the word session - so let's actually look at one of these things.You can trigger creation in the usual way: by breaching the CMA with an incorrect but maliciously intended login attempt:POST /login/?login_only=1 HTTP/1.1 Host: target:2087 Content-Type: application/x-www-form-urlencoded Content-Length: 20 user=root&pass=wrongcPanel (specifically cpsrvd) responds as follows (a polite way of saying get lost, punq):HTTP/1.1 401 Access Denied Set-Cookie: whostmgrsession=%3aWg_mjzgt1hyfXefK%2c1bd3d4bf5ecbf83b660789ab0f3198fa; HttpOnly; path=/; port=2087; secure Content-Type: text/plain; charset="utf-8" Content-Length: 38 {"status":0,"message":"see_login_log"}See that cookie? The only one? Did you find it yet?Well, if you URL-decode that cookie, you get :Wg_mjzgt1hyfXefK,1bd3d4bf5ecbf83b660789ab0f3198fa - a session name. Nothing unusual so far, much like our usual frenz PHPSESSID or JSESSIONID.At this point, cpsrvd has minted a "preauth" session and written it to disk. The on-disk file looks like this:$ cat /var/cpanel/sessions/raw/:Wg_mjzgt1hyfXefK local_ip_address=172.17.0.2 external_validation_token=bOOwkwVzFsruooU0 cp_security_token=/cpsess7833455106 needs_auth=1 origin_as_string=address=172.17.0.1,app=whostmgrd,method=badpass hulk_registered=0 tfa_verified=0 ip_address=172.17.0.1 local_port=2087 port=49254 login_theme=cpanel Why does the file exist if the login failed? For the usual reasons, like other frameworks and languages, because cpsrvd uses session files as a state machine across requests. The preauth session stores a pre-issued cp_security_token, the source IP for IP-locking, a 2FA verification flag, and more. When the user eventually logs in successfully, that same session gets upgraded with user=… and pass=… keys.But.. look at the name on disk. Then, look back at the URL-decoded cookie.What's that ,1bd3d4... part of the cookie? That's the <ob> segment. The 32 hex chars after the comma are a per-session secret (referred to as ob, used by Cpanel::Session::Encoder to symmetrically encode the pass field so it isn't sitting on disk in cleartext.In our friendly diff, we can see that <ob> is suspiciously close and involved in many changes:One in particular stands out:if ( defined $ob &&
Indicators of Compromise
- cve — CVE-2026-41940