CVE-2023-3479: Reflected XSS in HestiaCP
CVE-2023-3479: Reflected XSS in HestiaCP — How a Simple Script Led to a CVE
Introduction
During my security research, I discovered a reflected Cross-Site Scripting (XSS) vulnerability in HestiaCP - a popular open-source hosting control panel. This issue was later assigned CVE-2023-3479 and documented in the National Vulnerability Database.
Interestingly, the vulnerability was not found through traditional fuzzing or manual pentesting, but through a simple idea:
Extract all reachable paths from the codebase → request them → detect unparsed variables like
$_GET&$_POST.
This combination of static + dynamic analysis surfaced an endpoint that contained a reflected XSS.
High-Level Flow of My Detection Process
+---------------------------+
| Download Codebase |
+-------------+-------------+
|
v
+---------------------------+
| Enumerate All File Paths |
+-------------+-------------+
|
v
+-------------------------------------+
| Filter Only PHP / Processable Files |
+-------------+-----------------------+
|
v
+---------------------------+
| Build URLs for Each Path |
+-------------+-------------+
|
v
+---------------------------+
| Send HTTP GET Requests |
+-------------+-------------+
|
v
+-----------------------------------+
| If HTTP 200 → Inspect File for |
| $_GET / $_POST Usage |
+-------------+---------------------+
|
v
+---------------------------+
| Manual Verification (XSS) |
+---------------------------+
How I Automated the Discovery
I wanted a lightweight way to:
- Extract every PHP file and path from the codebase
- Request each one
- Detect unvalidated variables inside the file
- Prioritize only URLs returning HTTP 200
Combining these steps exposes endpoints that contain:
- reachable URLs
- unvalidated input handlers
Perfect targets for XSS and injection research.
The Script That Found the XSS
https://github.com/iamxhunt3r/smartfuzz
<?phpstream_context_set_default( ['ssl' => ['verify_peer' => false,'verify_peer_name' => false,],]);function checkUrl($url) {$headers = get_headers($url);return strpos($headers[0], '200') !== false;}function checkForUnparsedVariables($filename) {$content = file_get_contents($filename);if (strpos($content, '$_GET') !== false) {echo "Unparsed \$_GET variables found in: $filename\n";}if (strpos($content, '$_POST') !== false) {echo "Unparsed \$_POST variables found in: $filename\n";}}if ($argc < 3) {echo "Usage: php research_xss_fuzz.php <file_directory> <hostname>\n";exit(1);}$fileDirectory = $argv[1];$hostname = $argv[2];function getFilesInDirectory($dir) {global $fileDirectory;$fileList = [];$files = scandir($dir);foreach ($files as $file) {if ($file === '.' || $file === '..') continue;$fullPath = $dir . DIRECTORY_SEPARATOR . $file;if (is_dir($fullPath)) {$fileList = array_merge($fileList, getFilesInDirectory($fullPath));} else {$ext = pathinfo($fullPath, PATHINFO_EXTENSION);if (!in_array($ext, ['png','jpg','jpeg','gif','woff2','eot','svg','ttf','woff','css','js','mo','pot'])) {$fileList[] = str_replace($fileDirectory . '/', "", $fullPath);}}}return $fileList;}$files = getFilesInDirectory($fileDirectory);foreach ($files as $file) {$fullFilePath = $fileDirectory . DIRECTORY_SEPARATOR . $file;$url = "$hostname/$file";if (checkUrl($url)) {echo "HTTP 200 response for: $url\n";checkForUnparsedVariables($fullFilePath);}}?>
Running the script:
php research_xss_fuzz.php /path/to/hestiacp/ http://target.com
This revealed multiple valid paths and one particularly interesting endpoint returning:
- HTTP 200
- Unvalidated
$_GETvariable - Reflecting input directly into output
Which eventually led to the XSS.
Technical Breakdown of the Vulnerability
CVE ID: CVE-2023-3479
Type: Reflected Cross-Site Scripting
CVSS: 6.1
Component: HestiaCP web interface
The vulnerable parameter reflected user input without:
- Validation
- Encoding
- Sanitization
Example payload:
<script>alert('XSS')</script>
Successfully executed in the admin interface.
Attack Vector Diagram
Attacker
|
| 1. Sends malicious URL
v
Admin clicks URL
|
| 2. Payload reflected without sanitization
v
Browser executes JS
|
| 3. Attacker gains control
v
Account Compromise
Impact
An attacker could:
- Steal admin session tokens
- Execute privileged actions
- Redirect or manipulate UI
- Compromise the entire hosting panel
Remediation
The HestiaCP team fixed the issue by:
- Input validation
- Output sanitization
- Encoding reflected parameters
- Strengthening CSP headers
Timeline
- Discovery: March 2023
- Vendor Notified: March 2023
- CVE Assigned: June 2023
- Public Disclosure: July 2023
Thoughts on Automated Detection
While modern SAST tools and AI can detect unsanitized variables, my hybrid approach (static extraction + dynamic requests) still finds:
- Legacy code paths
- Hidden debug endpoints
- Panels with inconsistent sanitization
This simple script continues to have potential for expanding into a lightweight XSS research toolkit.
Conclusion
CVE-2023-3479 demonstrates how even minimal automation can reveal impactful vulnerabilities. The insight here is not the complexity of the bug, but the effectiveness of blending static and dynamic analysis using simple tooling.
References
- https://nvd.nist.gov/vuln/detail/CVE-2023-3479
- https://github.com/iamxhunt3r/smartfuzz
- https://hestiacp.com
- https://owasp.org/www-project-cheat-sheets/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
This blog post is for educational purposes and demonstrates the importance of responsible vulnerability disclosure.