GHSA-GCV3-5V9Q-FMHH

Vulnerability from github – Published: 2026-05-29 15:36 – Updated: 2026-06-09 11:54
VLAI
Summary
Froxlor has an authorization bypass in FTP shell assignment via missing server-side `available_shells` enforcement
Details

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:

// 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:

// 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:

// 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:

// 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:
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
  1. 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.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "froxlor/froxlor"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "2.3.6"
            },
            {
              "fixed": "2.3.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "2.3.6"
      ]
    }
  ],
  "aliases": [
    "CVE-2026-41235"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-29T15:36:26Z",
    "nvd_published_at": "2026-06-04T19:16:29Z",
    "severity": "HIGH"
  },
  "details": "### Summary\nFroxlor 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.\n\nAs 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.\n\n### Details\nThe 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:\n\n```php\n// customer_ftp.php:138-149\n$shells = [\n    \u0027/bin/false\u0027 =\u003e \u0027/bin/false\u0027\n];\n$availableshells = explode(\u0027,\u0027, Settings::Get(\u0027system.available_shells\u0027));\nif (is_array($availableshells) \u0026\u0026 !empty($availableshells)) {\n    foreach ($availableshells as $shell) {\n        $shells[trim($shell)] = trim($shell);\n    }\n}\n```\n\nThe request handler forwards posted form data directly into the FTP API command implementation:\n\n```php\n// customer_ftp.php:170-172\nif ($action == \u0027edit\u0027 \u0026\u0026 Request::post(\u0027send\u0027) == \u0027send\u0027) {\n    $result = $log-\u003elogAction(USR_ACTION, LOG_INFO, \"edited ftp-account #\" . $id);\n    Commands::get()-\u003eapiCall(\u0027Ftps.update\u0027, Request::postAll());\n}\n```\n\nOn 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`:\n\n```php\n// lib/Froxlor/Api/Commands/Ftps.php:119-123\nif (Settings::Get(\u0027system.allow_customer_shell\u0027) == \u00271\u0027 \u0026\u0026 $this-\u003egetUserDetail(\u0027shell_allowed\u0027) == \u00271\u0027) {\n    $shell = Validate::validate(trim($shell), \u0027shell\u0027, \u0027\u0027, \u0027\u0027, [], true);\n} else {\n    $shell = \u0027/bin/false\u0027;\n}\n```\n\nThe validated shell is stored into `ftp_users.shell` and later consumed by the root-owned cron task that rebuilds NSS extrausers files:\n\n```php\n// lib/Froxlor/Cron/System/Extrausers.php:89-97\n$passwd_entries[] = $user[\u0027username\u0027] . \u0027:x:\u0027 . $uid . \u0027:\u0027 . $gid . \u0027:\u0027 . $gecos . \u0027:\u0027 . $homedir . \u0027:\u0027 . $shell;\n```\n\nBecause 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.\n\n### PoC\nAn attacker needs a normal customer account and a deployment where customer shell delegation is enabled for that customer.\n\nRelevant runtime prerequisites:\n\n- `system.allow_customer_shell=1`\n- the attacking customer has `shell_allowed=1`\n- the deployment uses `system.nssextrausers=1` with the shipped `libnss-extrausers` integration\n\nFroxlor requires a valid CSRF token for POST requests, so the attacker performs the exploit from an authenticated session.\n\nComplete PoC flow:\n\n1. Log in as a customer and obtain a valid `csrf_token`.\n2. Identify one FTP account owned by that customer.\n3. Submit an edit request that sets an arbitrary shell outside the administrator-approved `system.available_shells` list:\n\n```http\nPOST /customer_ftp.php?page=accounts\u0026action=edit\u0026id=17 HTTP/1.1\nHost: target.example\nContent-Type: application/x-www-form-urlencoded\nCookie: \u003cauthenticated customer session\u003e\n\ncsrf_token=VALID_CSRF_TOKEN\u0026\nsend=send\u0026\nid=17\u0026\nusername=test1ftp1\u0026\nftp_description=poc\u0026\npath=/\u0026\nshell=/bin/bash\u0026\nlogin_enabled=1\n```\n\n4. Wait for Froxlor\u0027s master cron to process the queued `REBUILD_NSSUSERS` task.\n\nResult:\n\n- the request is accepted even if `/bin/bash` is not present in `system.available_shells`\n- `ftp_users.shell` is updated to `/bin/bash`\n- `/var/lib/extrausers/passwd` is regenerated with `/bin/bash` as the FTP user\u0027s login shell\n- the attacker can then authenticate to the host using that FTP user\u0027s credentials and obtain an interactive shell\n\n\n### Impact\nThis 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.\n\nBecause 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.",
  "id": "GHSA-gcv3-5v9q-fmhh",
  "modified": "2026-06-09T11:54:54Z",
  "published": "2026-05-29T15:36:26Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/froxlor/froxlor/security/advisories/GHSA-gcv3-5v9q-fmhh"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41235"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/froxlor/froxlor"
    },
    {
      "type": "WEB",
      "url": "https://github.com/froxlor/froxlor/releases/tag/2.3.7"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:P",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Froxlor has an authorization bypass in FTP shell assignment via missing server-side `available_shells` enforcement"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…