A hooded hacker’s laptop connects to a server dashboard, where a shield blocks a malware attack.
CWPdoor is the sort of malware that makes a sysadmin check the server twice. It is a new Linux malware distributed through a trojanized version of cwpsrv, the web server behind the Control Web Panel (CWP) management interface. It sits quietly until someone sends it a correctly signed request. It also tries to keep that request out of the access logs. The target is Linux, but Windows-centric IT teams often end up running mixed estates, hosting panels and web servers alongside their Microsoft stack. It is worth reading even if your daily driver is Windows Server.

A hooded hacker’s laptop connects to a server dashboard, where a shield blocks a malware attack. What was found​

XLab, the research arm of QiAnXin, published the analysis on November 5. Its researchers say CWPdoor is not a standalone program. The attacker inserted malicious code into the cwpsrv source and recompiled it, so the backdoor ships as a replacement for the real binary. cwpsrv itself is a customized, Nginx-based server that serves the CWP panel interface and its built-in applications.

XLab describes the malware as "exceptionally stealthy" because it triggers passively and suppresses logs. CWP, formerly CentOS Web Panel, is a free, open-source hosting panel. XLab says more than 340,000 CWP instances have been exposed on the public web over the past month. That number measures exposure, not compromise. XLab itself says only that those hosts are potential targets.

How the infection script works​

XLab spotted the malware on June 29 after capturing a script posing as an updater that swapped the legitimate cwpsrv binary for a malicious one. The script is named cwpsrv_update.sh. Per XLab's analysis:

  • It supports only cwpsrv versions 1.15.10 and 1.24.0, and must run as root. That describes what the script replaces. It does not mean every install of those versions is infected.
  • It checks the local version and downloads a matching binary. It then backs up the original, stops the service and overwrites /usr/local/cwpsrv/bin/cwpsrv.
  • It restarts the service and checks that the master, worker and helper processes are running. If that health check fails, it rolls back. If it succeeds, it deletes the temporary files and the backup.
  • It restores the binary's access and modification times, and the parent directory's timestamp, to their original values. It also runs history -d to remove the current session's command-history entry. Routine ls and stat checks therefore show a file that looks untouched.
  • It reports the result back to 136.0.141.71.

The trigger: a signed, encrypted HTTP request​

In normal use, the trojanized server behaves like cwpsrv. The backdoor activates only when a request carries three special headers:

HeaderPurpose
X-Ngx-Integrity-TimeTimestamp
X-Ngx-Integrity-DataEncrypted command
X-Ngx-Integrity-SigRSA signature

The checks work like this:

  1. The backdoor confirms the timestamp is within ±300 seconds.
  2. It verifies the signature against an RSA public key embedded in the binary. The signed value is the timestamp and data joined together.
  3. The command is Base64-encoded. After decoding, the first 16 bytes are the AES initialization vector and the rest is AES-256-CBC ciphertext. XLab says the key is derived from a SHA-256 digest of the embedded public-key string.
  4. The master process decrypts the command and passes it to a helper child process over a Unix domain socket.
  5. The result comes back encrypted, in an HTTP 200 response with content type application/octet-stream.

If any check fails, the request is handled as ordinary traffic and nothing visible happens. XLab says changing either the timestamp or the ciphertext independently invalidates the signature. That gives the operators replay protection, and it means a scanner or defender cannot trigger the backdoor without the attacker's private key.

Why the logs won't help​

When a request triggers the backdoor, the malware tampers with that request's module context and replaces the pointer for the logging module. The request never reaches the access log. A clean log therefore proves nothing here, and hunting for odd requests in access logs will miss this activity.

Evidence of real victims​

After the infection script, the researchers saw CWPdoor uploaded to VirusTotal on September 30 in an archive that also held the Ebury backdoor. The archive was named evidencia.tgz and was uploaded from Brazil. It held libkeyutils.so.1.5.2, which vendors identified as Ebury, and cwpsrv.suspeito. The cwpsrv file had zero detections. XLab concluded that the campaign was not merely experimental and that real victims exist. It did not name any victims or give a count.

Do not over-read the Ebury connection. XLab says the relationship is unclear and that the two families may have been planted on the same server by different attackers. For scale, ESET reported in May 2024 that Ebury had compromised nearly 400,000 Linux servers over almost 15 years. That total was cumulative, not simultaneous, and it says nothing about how many hosts carry CWPdoor.

What nobody knows yet​

XLab says it does not know how CWPdoor spreads or which vulnerability, if any, it uses. The script needs root, but the research does not show how attackers got that access. Treat this as an unattributed implant, not a confirmed CWP flaw.

Other CWP bugs do exist. Here is some context from separate reporting:

  • CVE-2025-67888 is an unauthenticated OS command injection flaw in CWP versions before 0.9.8.1209, and injected commands run as root.
  • In an earlier campaign, a threat actor scanned for CWP installs and exploited an old vulnerability to install a backdoor named Facefish.

Nothing in XLab's report ties CWPdoor to either of these. They show that the panel has been a recurring target and that root-level compromise of it is a known risk. They are not evidence of how this implant arrived.

How to check your servers​

XLab suggests three quick triage checks, run as root on a CWP host:

  1. Socket check: ss -axp | grep integrity. A match on the ngx_http_integrity_helper Unix socket is a red flag.
  2. Process check: ps aux | grep cwpsrv. Look for suspicious helper child processes tied to cwpsrv.
  3. Binary check: strings /usr/local/cwpsrv/bin/cwpsrv | grep X-Ngx-Integrity. Any hit means the header strings are in the binary.

These are triage indicators, not a full forensic procedure. A negative result is reassuring but does not clear the host, especially since the malware is built to hide. You can also search network and proxy telemetry for connections to 136.0.141.71 and compare binary hashes against XLab's indicators:

  • Script MD5: e505d4ffa21cf494a5dc2d7c8f4f1236
  • cwpsrv 1.15.10 sample MD5: 965aea67fb40de1bab5169ada993349f
  • cwpsrv 1.24.0 sample MD5: d3f4e95113d49ab3991b45e457bda75b

XLab lists these downloader URLs, defanged: http://136.0.141[.]71/static/cwpsrv_update.sh and the two version-specific binaries under the same path. Because the attackers recompile, other builds may have different hashes. Matching the socket and strings is more robust than hash matching alone.

If you find a hit​

XLab's recommended response:

  1. Replace the malicious binary with a legitimate copy. The attacker's backup may sit in /usr/local/cwpsrv/bin under a name like cwpsrv.prev-<date>-<time>. Verify any candidate before trusting it.
  2. Upgrade to the latest CWP version. Confirm that ss -axp | grep integrity no longer matches.
  3. Rotate all control panel credentials immediately. The backdoor runs arbitrary commands, so treat them as compromised.
  4. Treat the whole host as compromised and investigate it for other malware.

My own assessment, from general incident-response practice and not from XLab: for a root-level implant, rebuilding from a known-good image is usually safer than patching in place. Consider restoring from clean backups, and rotate SSH keys and any secrets stored on the box. Do not assume the backdoor is the only thing the attacker left behind.

Why admins should care​

The detail that worries me most is the zero-detection result at the time XLab examined the sample. Signature-based antivirus is blind to a freshly recompiled legitimate binary. A passive trigger, signed commands and suppressed logs also defeat the usual "watch the logs for weirdness" habit. Detection has to rely on host-level artifacts like sockets, process trees and binary strings, plus integrity monitoring that compares the binary against a trusted copy.

Practical steps for any shop running a hosting panel:

  • Do not expose admin panels directly to the internet. Restrict them to a VPN or an allowlist.
  • Use file-integrity monitoring on panel binaries, not just on web content.
  • Watch for unexpected binary replacement during "updates" that did not come from your package source.
  • Keep egress filtering tight, since the script phones home to a hard-coded address.

The story is still developing, because the infection route is unknown. XLab has invited peers with visibility into the campaign to share leads, so expect updates.

 

References

  1. Hackers backdoor Linux servers using trojanized CWP web server BleepingComputer 2026-11-05T11:24:26-05:00
  2. CVE-2025-67888: Control Web Panel (CWP) RCE Vulnerability sentinelone.com
  3. CWPdoor: The Invisible Backdoor Living Inside Control Web Panel blog.xlab.qianxin.com