Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-72876

CVE-2026-72876: Dokploy Multi-Tenant RCE Vulnerability

CVE-2026-72876 is a remote code execution vulnerability in Dokploy that allows attackers to execute arbitrary commands on another tenant's server. This article covers technical details, affected versions, and mitigation.

Published:

CVE-2026-72876 Overview

CVE-2026-72876 is a critical cross-tenant command injection vulnerability in Dokploy, a self-hostable Platform as a Service (PaaS). Versions prior to 0.29.13 fail to enforce organization ownership on Swarm read procedures and interpolate a caller-controlled nodeId into a remote shell command. An authenticated user with server:read permission can supply another organization's serverId and execute arbitrary commands as the configured SSH user on another tenant's server. The flaw is tracked under [CWE-78] OS Command Injection and combines an insecure direct object reference (IDOR) with unsafe shell interpolation.

Critical Impact

Any authenticated tenant with server:read can achieve remote code execution on servers owned by other organizations sharing the Dokploy instance.

Affected Products

  • Dokploy versions prior to 0.29.13
  • apps/dokploy/server/api/routers/swarm.ts (missing ownership check)
  • packages/server/src/services/docker.ts (getNodeInfo unsafe interpolation)

Discovery Timeline

  • 2026-08-10 - CVE-2026-72876 published to NVD
  • 2026-08-10 - Last updated in NVD database

Technical Details for CVE-2026-72876

Vulnerability Analysis

The vulnerability chains two defects in the Dokploy Swarm management API. The tRPC procedures swarm.getNodes, swarm.getNodeInfo, swarm.getNodeApps, and swarm.getAppInfos accept a serverId parameter without validating that the referenced server belongs to the caller's activeOrganizationId. This alone constitutes a cross-tenant IDOR that exposes Swarm metadata across organizations.

Downstream, getNodeInfo in packages/server/src/services/docker.ts builds a Docker command by interpolating the untrusted nodeId string directly into a shell invocation passed to execAsyncRemote. Because the SSH transport executes the composed string via a shell, standard metacharacters (;, `, $(...)) break out of the intended docker invocation. Combining both defects lets a low-privileged tenant target another organization's server and run arbitrary commands as the SSH user configured for that server.

Root Cause

The root cause is missing authorization on server-scoped read procedures combined with unsanitized command construction. The router did not call an ownership guard before dispatching to Swarm helpers, and execAsyncRemote received a shell string built through template literal interpolation instead of an escaped argument list.

Attack Vector

Exploitation requires a network-reachable Dokploy instance and an authenticated account holding the server:read permission in any organization on the shared instance. The attacker enumerates or guesses another tenant's serverId, then submits a crafted nodeId containing shell metacharacters to swarm.getNodeInfo. The server executes the injected payload over SSH against the victim tenant's host.

typescript
// Security patch: apps/dokploy/server/api/routers/swarm.ts
// fix(security): enforce org-scope on swarm reads and escape nodeId
import { createTRPCRouter, withPermission } from "../trpc";
import { containerIdRegex } from "./docker";

// Ensures a caller-supplied serverId belongs to the caller's active
// organization before any Swarm read runs against it. Without this, the
// server-scoped read procedures were reachable cross-organization (IDOR).
const assertServerInActiveOrg = async (
	serverId: string | undefined,
	activeOrganizationId: string | undefined,
) => {
	if (!serverId) return;
	const server = await findServerById(serverId);
	if (server.organizationId !== activeOrganizationId) {
		throw new TRPCError({
			code: "UNAUTHORIZED",
			message: "You are not authorized to access this server",
		});
	}
};

export const swarmRouter = createTRPCRouter({
	getNodes: withPermission("server", "read")
		.input(
			z.object({
				serverId: z.string().optional(),
			}),
		)
		.query(async ({ input, ctx }) => {
			await assertServerInActiveOrg(
// Source: https://github.com/Dokploy/dokploy/commit/5563699f71b2058b49eebdfd66c6c3dbd92ede9c

The companion fix in packages/server/src/services/docker.ts introduces shell-quote to escape node identifiers before they reach execAsyncRemote:

typescript
// Security patch: packages/server/src/services/docker.ts
import {
	execAsync,
	execAsyncRemote,
} from "@dokploy/server/utils/process/execAsync";
import { quote } from "shell-quote";

export const getContainers = async (serverId?: string | null) => {
	try {
// Source: https://github.com/Dokploy/dokploy/commit/5563699f71b2058b49eebdfd66c6c3dbd92ede9c

Detection Methods for CVE-2026-72876

Indicators of Compromise

  • Requests to tRPC endpoints swarm.getNodes, swarm.getNodeInfo, swarm.getNodeApps, or swarm.getAppInfos where the authenticated user's organization does not own the supplied serverId.
  • nodeId values containing shell metacharacters such as ;, &&, |, backticks, or $(...) in application logs.
  • Unexpected outbound connections, reverse shells, or new SSH sessions from Dokploy-managed Swarm nodes.
  • Anomalous processes spawned by the configured SSH user on managed hosts around the time of Swarm API calls.

Detection Strategies

  • Parse Dokploy application logs and correlate serverId values against the caller's activeOrganizationId to flag cross-tenant access attempts.
  • Alert on execAsyncRemote invocations whose command strings contain characters outside the expected Docker node identifier pattern.
  • Deploy host-based monitoring on Swarm nodes to identify child processes of the SSH daemon that do not match Docker binaries.

Monitoring Recommendations

  • Enable verbose tRPC request logging with authenticated user, organization, and input payload captured for audit review.
  • Forward Dokploy and Swarm host telemetry into a centralized data lake for behavioral analysis and retention.
  • Baseline normal Swarm API usage per tenant and alert on deviations in call volume or parameter shape.

How to Mitigate CVE-2026-72876

Immediate Actions Required

  • Upgrade Dokploy to version 0.29.13 or later on every node without delay.
  • Rotate SSH keys and credentials used by Dokploy to manage Swarm nodes after patching.
  • Audit organization membership and revoke server:read from accounts that no longer require it.
  • Review historical logs for cross-tenant serverId usage and suspicious nodeId payloads.

Patch Information

The fix ships in Dokploy 0.29.13, released via the GitHub Release v0.29.13. The patch is implemented in Pull Request #4858 and commit 5563699. Refer to the GitHub Security Advisory GHSA-jj6h-388v-9rwm for coordinated details. The fix adds assertServerInActiveOrg before Swarm reads and uses shell-quote to escape nodeId before shell execution.

Workarounds

  • Restrict Dokploy instance access to a single trusted organization until the upgrade is complete.
  • Remove the server:read permission from all non-administrator roles as a temporary compensating control.
  • Place the Dokploy management interface behind a VPN or identity-aware proxy to limit exposure to authenticated attackers.
bash
# Upgrade Dokploy to the patched release
docker pull dokploy/dokploy:0.29.13
docker service update --image dokploy/dokploy:0.29.13 dokploy

# Verify the running version
docker service inspect dokploy --format '{{.Spec.TaskTemplate.ContainerSpec.Image}}'

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.