Control Web Panel

WebPanel => CentOS-WebPanel Bugs => Topic started by: cestay on July 23, 2026, 08:28:15 PM

Title: Unauthenticated root RCE on 0.9.8.1244 — a SECOND api sink survives the CVE-2025
Post by: cestay on July 23, 2026, 08:28:15 PM
Hi CWP team,

I'm reporting an actively-exploited, unauthenticated remote command execution as root that affects a fully-updated 0.9.8.1244 panel. It looks like a variant of CVE-2025-67888 / KIS-2025-09 that the 0.9.8.1209 fix did not fully close: the patch sanitized one sink, but a second sink in the same api=1 code path is still reachable.

I'm posting here because there is no published security contact. I'm keeping the weaponized request, server identity and full logs out of this public post — I'll gladly share the complete PoC, raw logs and IOCs with a staff member privately. Please point me to a private channel (PM / email).

Summary

Technical description (sanitized)

The public CVE-2025-67888 injects through the key GET parameter of /admin/index.php?api=1&..., fixed in 0.9.8.1209.

On 0.9.8.1244 I observed a different injection point in the same handler:

Code: [Select]
GET /admin/index.php?api=1&key=<any-junk>&action=create_mysql_database&dbname=<INJECTION>
Two problems combine:

1. The API key check is broken, not just bypassed by a real key. With an empty admin_apis table (no keys configured), certain junk key values still pass the check and reach the action dispatch, while others are rejected — i.e. the validation returns success on malformed input rather than requiring a valid key.

2. The dbname value under action=create_mysql_database reaches a shell context unsanitized. A $(...) command-substitution in dbname executes as root. Other metacharacters ( ; | ) do NOT trigger it in my testing — only command substitution — consistent with the value being interpolated into a shell command string.

I reproduced it with a benign command (e.g. writing id output to a marker file); the marker was created owning uid=0(root). I am not including the live attack string here on purpose.

Important difference from CVE-2025-67888: that advisory lists Softaculous or SitePad as a prerequisite. My host had neither installed (no Softaculous/SitePad directories, no packages — verified). So this create_mysql_database sink does NOT depend on Softaculous/SitePad and is exploitable on a broader set of installs than the original CVE.

The 1209 changelog closed the key sink; this dbname/create_mysql_database path appears to have been missed. It may warrant its own CVE.

What the real attack did (for detection)

The attacker used the same request shape with a $(curl ... | bash) payload. cwpsrv (root) then fetched two remote files and installed:
Both had faked mtimes (2024) but true ctimes matching the intrusion time. Because the cloak is intermittent (~7%, C2-controlled), file/DB/checksum hunts came back clean at first — the smoking gun was the module linking libcurl and the cwpsrv root process spawning wget in /var/log/messages.

IOCs (share widely — same campaign is hitting other CWP hosts)

Mitigation that works today (for other admins reading this)

Until CWP patches, block the api parameter at the panel's front proxy. In cwpsrv/conf/cwp_panels.conf, inside the /admin and /api locations:

Code: [Select]
if ($arg_api) { return 403; }
# allow 127.0.0.1 first if you legitimately use the API (WHMCS/Blesta)

External api= -> 403; login/panel unaffected. This blocks BOTH the key and dbname sinks, not just the patched one. Also: restrict /admin by source IP, and remove Softaculous/SitePad if unused.

Ask to the CWP team

Happy to help reproduce. Thanks.
Title: Re: Unauthenticated root RCE on 0.9.8.1244 — a SECOND api sink survives the CVE-2025
Post by: Netino on July 23, 2026, 10:28:47 PM
To protect your server with an additional password for cwpsrv (nginx), please refer to this post:
https://forum.centos-webpanel.com/centos-webpanel-bugs/i-think-there-is-a-very-serious-security-vulnerability-in-cwp-right-now/msg53465/#msg53465 (https://forum.centos-webpanel.com/centos-webpanel-bugs/i-think-there-is-a-very-serious-security-vulnerability-in-cwp-right-now/msg53465/#msg53465)

This is not a CWP password; it is a password for *nginx*, which cwpsrv is based on.
It restricts access to everything under your CWP server's root directory.
You are free to use IP-based access only, or password-only access if you prefer. Alternatively, you can use both IP and password authentication.
This has worked very well for me for over two years.
I haven't had any issues with intrusions since then.

Best regards,
Netino