# Finding XSS in a million websites (cPanel CVE-2023-29489)

Unauthenticated reflected XSS in cPanel's /cpanelwebcall/ handler, reachable via Apache proxy on ports 80/443, enabling session hijack and webshell upload.

- Payout: Research
- Severity: high
- Program: cPanel
- Credited: Assetnote
- Disclosed: 2023-12-27
- CVE: CVE-2023-29489
- Write-up quality: 7/10
- Original: https://www.assetnote.io/resources/research/finding-xss-in-a-million-websites-cpanel-cve-2023-29489
- Library page: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-finding-xss-in-a-million-websites-cpanel-cve-2023-29489
- Tags: domain:web impact:ato impact:rce kind:research platform:research sev:high tech:nginx technique:source-review vuln:misconfiguration vuln:xss

**Target:** cPanel cpsrvd /cpanelwebcall/ endpoint proxied via Apache
**Root cause:** The webcall ID extracted from the URI path is passed unsanitized into message_html of Httpd::ErrorPage, which reflects it into the error response HTML without encoding.
**Steps:**
1. Read /etc/apache2/conf/httpd.conf to find `ProxyPass /cpanelwebcall/ http://127.0.0.1:2082/cpanelwebcall/`
2. Read Cpanel/Server/Handlers/Httpd.pm: paths starting with `/cpanelwebcall/` route to `_serve_cpanelwebcall(substr($doc_path,15))`
3. Trace to Cpanel::Server::WebCalls::handle -> extract_id_from_request -> is_valid fails -> `_http_invalid_params_err("Invalid webcall ID: $id")`
4. Error message flows into Httpd::ErrorPage `message_html` unencoded
5. Request `http://example.com/cpanelwebcall/<script>alert(1)</script>` on port 80/443 or 2082/2086
**How found:** Audited cPanel source shipped at /usr/local/cpanel; used httpd.conf proxy/script-alias rules to map pre-auth surface; read Httpd.pm comments describing a tiny HTTP server with whitelisted behaviors; followed the /cpanelwebcall/ branch into WebCalls::handle and the error path; confirmed sink via patch diff adding safe_html_encode_str.
**Exploitation:** Attacker lures a logged-in cPanel user to a crafted URL on the victim's own domain (port 80/443 proxied to cpsrvd); reflected JS executes in cPanel origin, hijacks the session, and the attacker uploads a webshell for command execution.
**Escalation:** XSS on management ports -> session hijack of authenticated cPanel user -> webshell upload -> RCE.
**Insight:** Apache ProxyPass rules in httpd.conf expose internal cpsrvd handlers on customer-facing ports 80/443 — enumerate proxy/script-alias directives to find pre-auth endpoints reachable without the management port; error-message reflection paths (invalid-param errors) are prime XSS sinks.
