Dokploy before 0.31.1 contains an OS command injection vulnerability in getComposeContainerCommand() that allows authenticated organization members to execute shell commands via the serviceName parameter. Attackers can store serviceName values with shell metacharacters through backup.create or backup.update tRPC procedures, executing commands as root when scheduled backups run and taking over the host via the mounted Docker socket.
Dokploy 0.28.0 before 0.31.1 contains a path traversal vulnerability that allows authenticated organization members to list tracked files of any git repository by supplying an arbitrary repoPath to patch.readRepoDirectories. Attackers with read access to one service can enumerate file and directory names of other tenants' application and compose source trees on the host or managed servers.
Dokploy 0.28.0 before 0.31.1 contains a path traversal vulnerability that allows authenticated organization members to read arbitrary files by supplying ../ sequences in the filePath of patch.readRepoFile. Attackers with service read permission can read /etc/shadow, SSH private keys, and secret environment files on the Dokploy host or managed remote servers.
Dokploy 0.28.0 before 0.31.1 contains a path traversal vulnerability that allows authenticated organization members to read arbitrary files by supplying ../ sequences in the filePath of patch.readRepoFile. Attackers with service read permission can read /etc/shadow, SSH private keys, and secret environment files on the Dokploy host or managed remote servers.
Dokploy 0.28.0 before 0.31.1 contains a path traversal vulnerability that allows authenticated organization members to list tracked files of any git repository by supplying an arbitrary repoPath to patch.readRepoDirectories. Attackers with read access to one service can enumerate file and directory names of other tenants' application and compose source trees on the host or managed servers.
Dokploy before 0.31.1 contains a missing ownership check vulnerability in the readAppMonitoring tRPC procedure that allows authenticated attackers to access container metrics belonging to other organizations by supplying an arbitrary appName. Attackers can query getApplicationStats with any application name, including the fixed "dokploy" control-plane service name, to read CPU, memory, network I/O, and block I/O metrics for containers they do not own on self-hosted multi-tenant instances.
Dokploy before 0.31.1 contains a missing ownership check vulnerability in the readAppMonitoring tRPC procedure that allows authenticated attackers to access container metrics belonging to other organizations by supplying an arbitrary appName. Attackers can query getApplicationStats with any application name, including the fixed "dokploy" control-plane service name, to read CPU, memory, network I/O, and block I/O metrics for containers they do not own on self-hosted multi-tenant instances.
Dokploy's pitch is a self-hosted panel that holds the keys to everything it manages: root on every server in the fleet, the Docker socket, and the credentials of every database and application it deploys. 38,000 stars, 514 official templates. The panel is, by design, the most trusted process on the host.
The validator allows the backtick. Tested against dokploy/dokploy v0.31.0 (official image, digest sha256:f836f0ab…0953):
1. The database password validator (DATABASEPASSWORDREGEX, packages/server/src/db/schema/utils.ts:51-52, in the code since v0.29.0) bans $, !, both quotes, backslash, slash and space. It allows the backtick — and ; | & ( ) > with it.
2. In the Postgres and MySQL changePassword procedures the new password is placed in single quotes nested inside a double-quoted shell argument, where bash still performs command substitution. A password consisting of a backtick command and a redirect — no slash, no space, no banned character — executes as the Dokploy server process: uid=0(root) in the container that holds the host's Docker socket.
3. databaseUser carries no validator at all (z.string().min(1)) and reaches Postgres unquoted. A semicolon in the username is a complete command sequence — no substitution trick required — and the field is settable both at creation and through update on a deployed service.
4. The MariaDB and Mongo changePassword sinks are source-identical in shape to the fired pair; they are claimed at source-level confidence and were not separately fired. The Redis sibling does not fire: its password sits in top-level single quotes, and that control is what proves the mechanism.
Live proof, against our own rig only (official v0.31.0 image, localhost-bound): a benign password changed cleanly (200); a $(id) password was rejected by the validator (400) — the control showing the guard alive and incomplete; the backtick password returned 200 and left a canary file reading uid=0(root) gid=0(root) inside the server container. Replicated once from a clean container state. The backtick and semicolon usernames fired the same way, and the MySQL password sink fired as a second, distinct sink.
Scope, stated plainly: this is not unauthenticated, and it is not a cross-organization failure. Every changePassword procedure first checks checkServicePermissionAndAccess with the service: ["create"] permission; the attacker is an organization member who holds that permission and access to the service — in practice, the member who deployed the database. In a single-admin install there is no boundary to cross. Dokploy's product is multi-tenant hosting, and the vendor scored this same precondition class 9.9 (CVE-2026-72868): the tenant who can deploy a database should not thereby own the host and every other tenant's secrets on it.
What held is credited at the same weight: a suspected cross-organization rollback path was tested and did not fire — the service functions throw before any effect, and the state is unreachable through product flows. The validator's author clearly enumerated the dangerous characters; the class that executes is the one the enumeration missed.
Canary, for the record: on 2026-11-09, after this measurement, the vendor rebuilt all five changePassword commands on the canary branch using shell-quote argv arrays. No release contains that rewrite; v0.31.0 — the current release and the installed base — is the vulnerable code, and the validator is unchanged on every branch.
Paper: https://archive.org/details/knell-the-seventh-site
Key: 133883AB9F6EDE5B9BA6B82E27BEDAF0CE152F25 (knell)
Verify: gpg --import knell-public.asc, then gpg --verify paper-dokploy-FINAL-2026-11-09.md.asc
— knell
More, signed and timestamped: https://github.com/the-knell
Dokploy through 0.30.10 contains an authorization bypass vulnerability that allows owners or admins of any organization to control other tenants' applications by supplying foreign applicationId values. Attackers can call procedures like saveEnvironment, updateTraefikConfig, deploy, or stop to overwrite environment variables and build secrets, repoint sources, and disrupt other tenants' applications.
Dokploy through 0.30.8 contains a cross-organization authorization bypass in the port tRPC router that allows authenticated owners or admins of any organization to manage other tenants' ports because the target application's organization is never verified. Attackers supplying a known portId or applicationId to port.create, port.one, port.update, or port.delete can read, modify, delete, or add port mappings, disrupting how victim services are published.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the patch.readRepoDirectories tRPC procedure passes the user-controlled repoPath value from apps/dokploy/server/api/routers/patch.ts into a shell command in packages/server/src/services/patch-repo.ts without safe argument quoting. An authenticated organization member with service:read permission can inject shell metacharacters into repoPath and execute arbitrary commands through childprocess.exec as root in the Dokploy container. The supplied service identifier is used only to resolve the server and does not constrain repoPath. Because the standard deployment mounts /var/run/docker.sock, container-root command execution can be used to control Docker and compromise the host and its managed applications. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, Dokploy organization members without Git provider access can retrieve plaintext provider credentials through github.one, gitlab.one, gitea.one, and bitbucket.one because those protected procedures return full provider rows without applying getAccessibleGitProviderIds or an organization check. The application.one route also returns nested GitHub, GitLab, Gitea, and Bitbucket relations from findApplicationById with GitHub App private keys, OAuth tokens, client secrets, webhook secrets, and app passwords even when hasGitProviderAccess is false. A member with application read access or a provider identifier can therefore bypass per-member provider assignment and use the exposed credentials to access private repositories or manipulate external workflows. This issue is fixed in version 0.29.13.
A vulnerability was detected in Dokploy up to 0.29.7. This issue affects the function writeTraefikConfigInPath of the file packages/server/src/utils/traefik/application.ts of the component Settings. The manipulation of the argument path results in path traversal. The attack can be launched remotely. The exploit is now public and may be used. The vendor was contacted early about this disclosure but did not respond in any way.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, Dokploy allows an authenticated user to execute arbitrary commands on a local or SSH-connected target server because registry.testRegistry and registry.testRegistryById in apps/dokploy/server/api/routers/registry.ts interpolate the password field into an execAsyncRemote shell command instead of using safeDockerLoginCommand. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, Dokploy allows an authenticated low-privilege member to execute arbitrary commands on the control-plane host because the volumeName field accepted by volumeBackup.create and volumeBackup.runManually is interpolated without quoting in packages/server/src/utils/volume-backups/backup.ts and executed through childprocess.exec, with Docker socket access making execution host/root-equivalent. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, sanitizeCommand in packages/server/src/utils/builders/compose.ts only trims whitespace and strips surrounding quotes from compose.command before exportEnvCommand and docker command interpolation, allowing an authenticated user who can update a Compose service to inject shell metacharacters and execute arbitrary commands on the Dokploy host. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the WebSocket handlers in apps/dokploy/server/wss/terminal.ts, apps/dokploy/server/wss/docker-container-terminal.ts, apps/dokploy/server/wss/docker-container-logs.ts, and apps/dokploy/server/wss/docker-stats.ts validate organization membership but do not enforce checkServiceAccess, accessedServerIds, or accessedServices, allowing an authenticated organization member to obtain root terminal access and read logs or statistics for restricted servers and services. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the dockerImage field is interpolated without quoting into shell commands in buildRemoteDocker() in packages/server/src/utils/providers/docker.ts and is validated only as an optional string. An authenticated user with application create or update permission can use shell command substitution in dockerImage to execute arbitrary commands on the local build host or a remote SSH build target, exposing host secrets and other projects. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, swarm.getNodes, swarm.getNodeInfo, swarm.getNodeApps, and swarm.getAppInfos in apps/dokploy/server/api/routers/swarm.ts accept another organization’s serverId without an activeOrganizationId ownership check, and getNodeInfo in packages/server/src/services/docker.ts interpolates nodeId into execAsyncRemote, allowing a caller with server:read permission to execute arbitrary commands as the configured SSH user on another tenant’s server. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, cloneGitRepository in packages/server/src/utils/providers/git.ts interpolates customGitUrl and customGitBranch into a git clone command passed to execAsync or execAsyncRemote, allowing an authenticated user with application access to execute arbitrary operating system commands on the Dokploy host by setting a malicious custom Git URL and triggering deployment. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, application.saveBitbucketProvider stores bitbucketOwner and bitbucketRepository without validation and cloneBitbucketRepository in packages/server/src/utils/providers/bitbucket.ts interpolates those values into git clone commands executed through execAsync or execAsyncRemote, allowing a member with service deployment permission to execute arbitrary operating system commands on the Dokploy host or target server. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the unauthenticated /api/providers/github/setup route in apps/dokploy/pages/api/providers/github/setup.ts trusts ghinit organizationId and userId values from the state parameter and calls createGithub in packages/server/src/services/github.ts, allowing an attacker to insert a GitHub App provider containing clientsecret, webhooksecret, and PEM private key material into another organization. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the backup.restoreBackupWithLogs tRPC subscription passes the databaseName parameter to restore builders in packages/server/src/utils/restore/utils.ts, where PostgreSQL, MariaDB, MySQL, and MongoDB commands embed the 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, resulting in arbitrary commands running in the Docker-privileged host context. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, apps/dokploy/server/api/routers/destination.ts interpolates the accessKey, secretAccessKey, region, endpoint, provider, and bucket fields from destination.testConnection into an rclone ls command executed through childprocess.exec. The withPermission("destination", "create") path permits a low-privileged organization member to reach the mutation, close a quoted argument with a crafted field, and execute arbitrary commands in the root Dokploy container, which has access to the host Docker socket. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the WebSocket handler in apps/dokploy/server/wss/terminal.ts validates a session but does not authorize access to the requested server. An authenticated user can connect to /terminal?serverId=local, select the special serverId=local branch, and obtain an interactive terminal on the Dokploy host without an organization role or server-access check. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the compose.update operation stores an unvalidated composePath that packages/server/src/utils/builders/compose.ts and packages/server/src/services/compose.ts interpolate into docker compose -f, docker stack deploy -c, and touch shell commands executed through /bin/sh -c. An authenticated member with compose write and deploy permission can supply a crafted composePath, trigger compose.deploy or startCompose, and execute arbitrary operating-system commands in the Docker-privileged Dokploy host context. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the local branch of /docker-container-terminal in apps/dokploy/server/wss/docker-container-terminal.ts authenticates with validateRequest but does not authorize the attacker-controlled containerId against the caller's role, organization, or service access before passing it to docker exec, allowing any authenticated member to obtain a root shell in arbitrary containers on a self-hosted instance. This issue is fixed in version 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, Dokploy's WebSocket handlers (in-app terminals and log streamers) authenticate the session but never authorize it. They establish who the user is via validateRequest() and then proceed without consulting the role/permission model that every tRPC procedure enforces. Any authenticated member, can therefore open an interactive shell into any container on the host, including the dokploy container that mounts the Docker socket, and from there obtain root on the host, escaping the application and crossing every tenant boundary. This vulnerability is fixed in 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, the mariadb.ts, mongo.ts, mysql.ts, postgres.ts, redis.ts, and libsql.ts Dokploy database service deployment functions pass user-controlled dockerImage fields unquoted into docker pull ${dockerImage} shell commands on the remote-server code path. This vulnerability is fixed in 0.29.13.
Dokploy is a free, self-hostable Platform as a Service (PaaS). Prior to 0.29.13, packages/server/src/utils/providers/git.ts parses the user-controlled customGitUrl with sanitizeRepoPathSSH and interpolates its domain into the ssh-keyscan command from addHostToKnownHostsCommand without shell quoting, allowing an authenticated member with service deployment permission and an attached SSH key to execute arbitrary commands on the Dokploy host during deployment. This issue is fixed in version 0.29.13.