Froxlor 2.3.6 fails to enforce the administrator-configured shell whitelist server-side, allowing any authenticated customer with shell delegation enabled to submit an arbitrary shell (e.g., /bin/bash) that gets materialized as the OS-level login shell by a root-owned provisioning cron. This is directly relevant to teams using Froxlor-managed shared hosting for AI/ML workloads — Jupyter notebooks, Streamlit apps, model APIs, vector databases — where a compromised co-tenant gains the ability to traverse tenant boundaries and access model weights, training datasets, and stored API keys. With CVSS 8.8, 469 downstream dependents, trivial exploitation requiring only a valid customer account, and default installer settings meeting all prerequisites, this warrants immediate action on any Froxlor deployment hosting AI workloads. Patch to Froxlor 2.3.7 immediately, or as an interim workaround disable system.allow_customer_shell in panel settings; audit the ftp_users.shell column for any entries outside your approved shell whitelist.
What is the risk?
HIGH. Exploitation requires only a valid customer account and Froxlor's default installer configuration (nssextrausers=1, allow_customer_shell=1 with per-customer delegation), making this broadly exploitable on shared hosting deployments without any specialized AI or security knowledge. The attacker's shell is materialized at the OS level by a root-owned cron, meaning the foothold survives panel-level remediation that does not also purge the NSS extrausers database. The jump from FTP-restricted tenant to interactive host shell dramatically expands blast radius: lateral movement to co-hosted services, credential harvesting from .env files, and persistent access. Not yet in CISA KEV and no public scanner template, but the PoC is a single crafted POST request — exploitation difficulty is trivial once prerequisites are confirmed.
Attack Kill Chain
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| froxlor/froxlor | composer | = 2.3.6 | 2.3.7 |
Do you use froxlor/froxlor? You're affected.
Severity & Risk
Attack Surface
What should I do?
6 steps-
Patch to Froxlor 2.3.7 immediately — this release adds server-side whitelist enforcement in Ftps::add() and Ftps::update().
-
If immediate patching is not possible, disable system.allow_customer_shell in Froxlor Settings → FTP to prevent any customer from setting a shell value. Alternatively, set system.nssextrausers=0 to prevent shell propagation to the OS layer (requires restart of NSS services).
-
Audit for existing exploitation: run SELECT username, shell FROM ftp_users WHERE shell NOT IN (SELECT trim(unnest(string_to_array(value, ','))) FROM settings WHERE settingname = 'system.available_shells') on the Froxlor PostgreSQL instance.
-
Inspect /var/lib/extrausers/passwd for unauthorized shell entries (/bin/bash, /bin/sh, etc.) and manually correct any found.
-
Review SSH and FTP authentication logs for customer accounts that subsequently established interactive shell sessions.
-
Enforce network-level controls restricting SSH access to known administrator IP ranges, removing SSH as an accessible attack surface for customer accounts.
Classification
Compliance Impact
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-41235?
Froxlor 2.3.6 fails to enforce the administrator-configured shell whitelist server-side, allowing any authenticated customer with shell delegation enabled to submit an arbitrary shell (e.g., /bin/bash) that gets materialized as the OS-level login shell by a root-owned provisioning cron. This is directly relevant to teams using Froxlor-managed shared hosting for AI/ML workloads — Jupyter notebooks, Streamlit apps, model APIs, vector databases — where a compromised co-tenant gains the ability to traverse tenant boundaries and access model weights, training datasets, and stored API keys. With CVSS 8.8, 469 downstream dependents, trivial exploitation requiring only a valid customer account, and default installer settings meeting all prerequisites, this warrants immediate action on any Froxlor deployment hosting AI workloads. Patch to Froxlor 2.3.7 immediately, or as an interim workaround disable system.allow_customer_shell in panel settings; audit the ftp_users.shell column for any entries outside your approved shell whitelist.
Is CVE-2026-41235 actively exploited?
No confirmed active exploitation of CVE-2026-41235 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-41235?
1. Patch to Froxlor 2.3.7 immediately — this release adds server-side whitelist enforcement in Ftps::add() and Ftps::update(). 2. If immediate patching is not possible, disable system.allow_customer_shell in Froxlor Settings → FTP to prevent any customer from setting a shell value. Alternatively, set system.nssextrausers=0 to prevent shell propagation to the OS layer (requires restart of NSS services). 3. Audit for existing exploitation: run SELECT username, shell FROM ftp_users WHERE shell NOT IN (SELECT trim(unnest(string_to_array(value, ','))) FROM settings WHERE settingname = 'system.available_shells') on the Froxlor PostgreSQL instance. 4. Inspect /var/lib/extrausers/passwd for unauthorized shell entries (/bin/bash, /bin/sh, etc.) and manually correct any found. 5. Review SSH and FTP authentication logs for customer accounts that subsequently established interactive shell sessions. 6. Enforce network-level controls restricting SSH access to known administrator IP ranges, removing SSH as an accessible attack surface for customer accounts.
What systems are affected by CVE-2026-41235?
This vulnerability affects the following AI/ML architecture patterns: Shared hosting AI/ML deployments, Model serving infrastructure, ML development environments, Multi-tenant AI API hosting.
What is the CVSS score for CVE-2026-41235?
CVE-2026-41235 has a CVSS v3.1 base score of 8.8 (HIGH).
AI Security Impact
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0012 Valid Accounts AML.T0037 Data from Local System AML.T0049 Exploit Public-Facing Application AML.T0105 Escape to Host Compliance Controls Affected
Technical Details
Original Advisory
### Summary Froxlor 2.3.6 lets administrators configure `system.available_shells` as the approved shell list that customers may assign to FTP users. However, the server-side FTP account handlers do not enforce that whitelist when processing add or edit requests. As a result, an authenticated customer with shell delegation enabled can submit an arbitrary shell such as `/bin/bash` even when the panel UI only offers more restricted choices. In deployments that use the default `nssextrausers` integration, the attacker-controlled shell is then propagated into the system account database, leading to real host shell access. ### Details The customer-facing FTP account page builds the shell selector from `system.available_shells`, which shows that the product intends the setting to act as the authorization boundary: ```php // customer_ftp.php:138-149 $shells = [ '/bin/false' => '/bin/false' ]; $availableshells = explode(',', Settings::Get('system.available_shells')); if (is_array($availableshells) && !empty($availableshells)) { foreach ($availableshells as $shell) { $shells[trim($shell)] = trim($shell); } } ``` The request handler forwards posted form data directly into the FTP API command implementation: ```php // customer_ftp.php:170-172 if ($action == 'edit' && Request::post('send') == 'send') { $result = $log->logAction(USR_ACTION, LOG_INFO, "edited ftp-account #" . $id); Commands::get()->apiCall('Ftps.update', Request::postAll()); } ``` On the server side, `Ftps::add()` and `Ftps::update()` only perform generic shell string validation. They do not verify that the submitted shell belongs to `system.available_shells`: ```php // lib/Froxlor/Api/Commands/Ftps.php:119-123 if (Settings::Get('system.allow_customer_shell') == '1' && $this->getUserDetail('shell_allowed') == '1') { $shell = Validate::validate(trim($shell), 'shell', '', '', [], true); } else { $shell = '/bin/false'; } ``` The validated shell is stored into `ftp_users.shell` and later consumed by the root-owned cron task that rebuilds NSS extrausers files: ```php // lib/Froxlor/Cron/System/Extrausers.php:89-97 $passwd_entries[] = $user['username'] . ':x:' . $uid . ':' . $gid . ':' . $gecos . ':' . $homedir . ':' . $shell; ``` Because the default installer configuration sets `system.nssextrausers=1`, and the shipped Debian/Bookworm configuration enables `extrausers` in `nsswitch.conf`, the attacker-controlled shell becomes the effective login shell of the generated system user on standard supported deployments. ### PoC An attacker needs a normal customer account and a deployment where customer shell delegation is enabled for that customer. Relevant runtime prerequisites: - `system.allow_customer_shell=1` - the attacking customer has `shell_allowed=1` - the deployment uses `system.nssextrausers=1` with the shipped `libnss-extrausers` integration Froxlor requires a valid CSRF token for POST requests, so the attacker performs the exploit from an authenticated session. Complete PoC flow: 1. Log in as a customer and obtain a valid `csrf_token`. 2. Identify one FTP account owned by that customer. 3. Submit an edit request that sets an arbitrary shell outside the administrator-approved `system.available_shells` list: ```http POST /customer_ftp.php?page=accounts&action=edit&id=17 HTTP/1.1 Host: target.example Content-Type: application/x-www-form-urlencoded Cookie: <authenticated customer session> csrf_token=VALID_CSRF_TOKEN& send=send& id=17& username=test1ftp1& ftp_description=poc& path=/& shell=/bin/bash& login_enabled=1 ``` 4. Wait for Froxlor's master cron to process the queued `REBUILD_NSSUSERS` task. Result: - the request is accepted even if `/bin/bash` is not present in `system.available_shells` - `ftp_users.shell` is updated to `/bin/bash` - `/var/lib/extrausers/passwd` is regenerated with `/bin/bash` as the FTP user's login shell - the attacker can then authenticate to the host using that FTP user's credentials and obtain an interactive shell ### Impact This issue lets a low-privileged customer bypass an administrator-defined authorization boundary and promote an FTP-only account into a real shell account. On shared-hosting systems managed by Froxlor, that materially changes the trust model and can expose the host to lateral movement, local privilege-escalation follow-on attacks, data theft from colocated services, and persistence on the server. Because the vulnerable flow is executed through the normal authenticated web interface and a root-owned provisioning task later materializes the chosen shell at the operating-system level, the vulnerability is stronger than a UI-only restriction bypass.
Exploitation Scenario
An attacker operating a standard customer account on a Froxlor-hosted environment — perhaps a small hosting provider running AI inference endpoints or Jupyter notebooks for multiple tenants — identifies that shell delegation is enabled for their account. They log into the customer panel, obtain a valid CSRF token from the FTP management page, and submit a single crafted POST to /customer_ftp.php?page=accounts&action=edit&id=<ftp_id> with shell=/bin/bash in the body. The panel validates only that the shell string is well-formed, accepts the request, and stores /bin/bash in ftp_users.shell. Within minutes, Froxlor's master cron processes the REBUILD_NSSUSERS task, regenerating /var/lib/extrausers/passwd with /bin/bash as the attacker's OS-level login shell. The attacker then SSHs into the host using their FTP credentials, browses co-tenant directories containing model weights, API keys, and training datasets, exfiltrates sensitive AI artifacts, and establishes persistence by dropping an SSH authorized key.
Weaknesses (CWE)
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H References
Timeline
Related Vulnerabilities
CVE-2026-41236 8.8 Froxlor: symlink-following grants customer root SSH access
Same package: panel CVE-2026-44898 6.1 mistune: XSS in TOC render via unescaped heading ID
Same package: panel CVE-2026-44708 6.1 mistune: math plugin XSS bypasses escape=True control
Same package: panel CVE-2026-44897 6.1 mistune: XSS via unescaped heading id= attribute
Same package: panel CVE-2026-44899 4.7 mistune: CSS injection enables phishing UI overlay
Same package: panel