CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-24841

PaaS-word to Pwnage: Breaking Dokploy with WebSocket Command Injection

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 30, 2026·6 min read·28 visits

Executive Summary (TL;DR)

Dokploy < 0.26.6 lets authenticated users pass unsanitized input into a shell command intended to spawn a Docker terminal. This allows attackers to break out of the `docker exec` command and run arbitrary code on the host server as root (or the service user). Fix: Upgrade to 0.26.6.

A critical command injection vulnerability in Dokploy's WebSocket terminal endpoint allows authenticated users to escape the confines of a Docker container session and execute arbitrary commands on the host operating system. By manipulating the parameters sent during the WebSocket handshake, attackers can abuse the server's use of shell interpolation to hijack the underlying process spawning logic.

The Hook: Your Cloud, My Command

PaaS (Platform as a Service) solutions like Dokploy are the darlings of the modern developer stack. They promise the ease of Heroku with the cost-savings of self-hosting. You give them a server, they give you a dashboard to deploy your Next.js apps and Postgres databases with a single click. It's magic. But as any stage magician knows, the trick is usually just hiding the messy reality behind a curtain.

One of the coolest features of these dashboards is the ability to shell directly into your running containers from the browser. It feels powerful. It feels like ssh, but over HTTP. However, implementing a web-based terminal is surprisingly treacherous territory. It requires taking user input from a WebSocket, piping it into a pseudo-terminal (PTY) on the server, and connecting that to a process.

Dokploy's implementation of this feature, specifically in the /docker-container-terminal endpoint, decided to take a shortcut through the most dangerous neighborhood in code-town: sh -c. Instead of carefully handling process arguments, it trusted the user to play nice. Spoiler alert: users do not play nice.

The Flaw: A Classic Shell Game

The vulnerability lives in how Dokploy spawns the interactive terminal session. When you click that "Terminal" tab in the UI, the frontend opens a WebSocket connection. During this handshake, it sends two key pieces of information: the containerId (which container do you want to enter?) and the activeWay (what shell do you want to run, like /bin/bash or /bin/sh).

In a secure world, the server would say, "Okay, I will run the binary docker with the arguments exec, -it, [containerId], and [shell]." This treats the arguments as raw strings.

But Dokploy didn't do that. Instead, it constructed a string using template literals—Javascript's way of gluing text together. It built a command string like this:

docker exec -it -w / ${containerId} ${activeWay}

And then—this is the kill shot—it passed that entire string to a shell for execution. The code effectively did bash -c "docker exec ...".

If you know anything about bash, you know it treats certain characters as control instructions. Semicolons, ampersands, backticks—these aren't just text to bash; they are orders. By failing to sanitize the input or use an argument array, Dokploy allowed parameters to become instructions.

The Code: Anatomy of a Disaster

Let's look at the crime scene. The vulnerable code was located in apps/dokploy/server/wss/docker-container-terminal.ts. Here is the logic that accepted the WebSocket connection and spawned the process.

The Vulnerable Code (Pre-0.26.6):

// The inputs come directly from the request
const { containerId, activeWay } = query;
 
// ... 
 
const shell = getShell(); // Returns the system shell
// THE SMOKING GUN:
const ptyProcess = spawn(
    shell,
    // This array implies the first arg is '-c' and the second is the command string
    ["-c", `docker exec -it -w / ${containerId} ${activeWay}`],
    {},
);

See that ${containerId}? That is unadulterated user input being pasted directly into a command string that shell is about to parse. The developer assumed containerId would be a hex string like a1b2c3d4. But what if it isn't?

The Fix (Commit 74e0bd5fe3ef7199f44fcd19c6f5a2f09b806d6f):

The patch does two things: it validates the input format (regex police!) and, more importantly, it stops using the shell to spawn the process.

// 1. Validation
if (!isValidContainerId(containerId)) {
    ws.close(4000, "Invalid container ID format");
    return;
}
 
// 2. Safe Spawn (No shell interpolation)
const ptyProcess = spawn(
    "docker", // Executing the binary directly
    ["exec", "-it", "-w", "/", containerId, shell], // Arguments as an array
    {},
);

By passing arguments as an array, docker receives the inputs literally. Even if you somehow bypassed the regex and passed ; rm -rf /, the docker binary would just complain that it can't find a container named ; rm -rf /.

The Exploit: Escaping the Sandbox

Exploiting this requires authentication, but "authenticated" in a multi-tenant or team environment is a low bar. Once we have a session, we can manually initiate a WebSocket connection. We don't need to use the UI; we can use wscat or a custom Python script.

The Attack Chain:

  1. Login: Obtain a valid session cookie or JWT.
  2. Connect: Open a WebSocket to ws://target/docker-container-terminal.
  3. Inject: We manipulate the query parameters. We can inject into containerId or activeWay.

Payload Construction:

If we send containerId as $(id) and activeWay as sh, the server executes: bash -c "docker exec -it -w / $(id) sh"

The shell sees $() and executes the id command on the host before passing the result to docker. That's cute, but we want more. We want to break the chain.

The "Game Over" Payload:

Let's set activeWay to sh; cat /etc/passwd. The server executes: bash -c "docker exec -it -w / [id] sh; cat /etc/passwd"

  1. docker exec ... sh runs. It might fail or succeed, we don't care.
  2. ; tells bash "finished with that, what's next?"
  3. cat /etc/passwd runs on the host server.

Because Dokploy is a management tool, it likely runs as root (to control the Docker daemon) or a highly privileged user. This is a full host takeover. We aren't stuck inside the container; we are on the captain's bridge.

The Impact: Why Severity is 9.9

You might wonder, "If I need to be authenticated, why is this a 9.9 and not an 8.something?" The answer lies in the Scope Change (S:C) metric of CVSS.

The vulnerability exists in the application layer (Dokploy), but the impact affects the underlying operating system (the Host). The attacker breaks out of the security context of the web application and gains control over the infrastructure itself.

Furthermore, in many deployment scenarios, developers might share a Dokploy instance. If a disgruntled contractor or a compromised junior dev account exploits this, they don't just mess up their own project; they own the entire server. They can dump the databases of other projects, steal environment variables (AWS keys, anyone?), install crypto miners, or pivot to the internal network.

It is effectively a "God Mode" cheat code for anyone with a login.

The Fix: Remediation

If you are running Dokploy versions prior to 0.26.6, stop reading this and update. Now.

Official Fix

Update your Dokploy instance via the manager or pull the latest Docker image: docker pull dokploy/dokploy:latest

Temporary Mitigation

If you cannot update immediately (why?), you must restrict access to the dashboard. Use a WAF or a reverse proxy (like Nginx) to block requests to /docker-container-terminal that contain suspicious characters ($, ;, &, |) in the query string.

However, WAF rules are notoriously bypassable. The only real fix is code that doesn't treat user input like a trusted friend. Trust no one, especially not a string from the internet.

Official Patches

DokployGitHub Commit fixing the vulnerability

Fix Analysis (1)

Technical Appendix

CVSS Score
9.9/ 10
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L
EPSS Probability
0.25%
Top 52% most exploited

Affected Systems

Dokploy < 0.26.6

Affected Versions Detail

Product
Affected Versions
Fixed Version
Dokploy
Dokploy
< 0.26.60.26.6
AttributeDetail
CVE IDCVE-2026-24841
CVSS9.9 (Critical)
CWECWE-78 (OS Command Injection)
Attack VectorNetwork (Authenticated)
ImpactRemote Code Execution (RCE) as Host User
Fix Version0.26.6

MITRE ATT&CK Mapping

T1059.004Command and Scripting Interpreter: Unix Shell
Execution
T1203Exploitation for Client Execution
Execution
T1611Escape to Host
Privilege Escalation
CWE-78
OS Command Injection

Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Known Exploits & Detection

HypotheticalExploitation involves sending crafted query parameters to the WebSocket endpoint.

Vulnerability Timeline

Vulnerability fixed in commit 74e0bd5
2026-01-27
CVE-2026-24841 Published
2026-01-28
GHSA-vx6x-6559-x35r Published
2026-01-28

References & Sources

  • [1]GitHub Security Advisory
  • [2]NVD Detail

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 1 hour ago•GHSA-69QJ-PVH9-C5WG
7.5

GHSA-69QJ-PVH9-C5WG: Command Injection in yt-dlp `--exec` Option

An OS command injection vulnerability in yt-dlp before 2026.06.09 allows unauthenticated remote attackers to execute arbitrary shell commands via crafted media metadata when a user processes media using the --exec post-processing parameter with unsafe string interpolation conversions.

Alon Barad
Alon Barad
5 views•7 min read
•about 2 hours ago•GHSA-7CX2-G3H9-382P
8.1

GHSA-7CX2-G3H9-382P: Multiple Vulnerabilities in Crawl4AI Docker API (Arbitrary File Write, SSRF, CRLF Log Injection)

An in-depth technical analysis of multiple security vulnerabilities in the self-hosted Docker API server of Crawl4AI up to version 0.8.7. These flaws include a critical arbitrary file write via symlink traversal and TOCTOU weakness, CRLF log injection, webhook header injection, and SSRF filter gaps. These have been remediated in version 0.8.8.

Alon Barad
Alon Barad
3 views•6 min read
•about 3 hours ago•GHSA-F989-C77F-R2CQ
8.2

GHSA-f989-c77f-r2cq: LLM Credential Exfiltration and SSRF in Crawl4AI Docker Server

A technical evaluation of the Crawl4AI open-source web crawling and scraping library revealed a high-severity credential exfiltration vulnerability in its self-hosted Dockerized API server. The flaw arises from an unvalidated base_url parameter in request payloads and a dynamic prefix resolution mechanism that retrieves system environment variables. Unauthenticated remote attackers can leverage these features in tandem to extract host-level secrets or redirect configured LLM API keys to an external listener under their control.

Amit Schendel
Amit Schendel
5 views•6 min read
•about 3 hours ago•GHSA-365W-HQF6-VXFG
9.8

GHSA-365w-hqf6-vxfg: Multiple Critical Vulnerabilities in Crawl4AI Docker API Server

The Crawl4AI Docker API server, in versions 0.8.6 and prior, contains multiple critical vulnerabilities including improper path sanitization, missing authentication on administration routes, hardcoded JWT secrets, and SSRF. These vulnerabilities allow remote, unauthenticated attackers to write arbitrary files, execute arbitrary code, and pivot into private cloud environments.

Amit Schendel
Amit Schendel
6 views•7 min read
•about 6 hours ago•GHSA-534H-C3CW-V3H9
5.5

GHSA-534h-c3cw-v3h9: Local Information Disclosure via Abstract-Namespace Socket in Nuxt Dev Server

A local security vulnerability in the Nuxt development server (nuxt dev) allows local unprivileged users to access sensitive configuration files and source code. On Linux environments running Node.js 20+, Nuxt bound its internal vite-node IPC server to an abstract-namespace Unix socket without any peer authentication, enabling co-resident local users to connect and request module code directly.

Amit Schendel
Amit Schendel
5 views•5 min read
•about 7 hours ago•GHSA-8RFP-98V4-MMR6
0.0

GHSA-8RFP-98V4-MMR6: Protocol-Filtering Bypass via Unicode Obfuscation in Mozilla Bleach

Mozilla Bleach is an open-source HTML sanitizing library for Python. Versions up to and including 6.3.0 contain an incomplete filtering implementation in the URI validation logic ('sanitize_uri_value'). This logic fails to detect disallowed protocols, such as 'javascript:', if they contain Unicode invisible characters, whitespace characters, or characters with a code point greater than U+00A0. While standard-compliant web browsers do not directly execute invalid URI schemes containing these non-standard characters, downstream systems that normalize Unicode text by stripping invisible or non-ASCII characters can unintentionally reactivate the 'javascript:' prefix, causing Cross-Site Scripting (XSS). Additionally, this behavior violates Bleach's core sanitization contract by outputting URIs that bypass protocol allowlists configured by the caller.

Amit Schendel
Amit Schendel
5 views•7 min read