Dokploy / Dokploy/dokploy

Secrets (SSH deploy key, TLS certificate private key) interpolated into shell commands and logged unredacted (CWE-532)

Open
#4,600 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
37.4k
Forks
3k
Avg merge
1d 3h
Merged PRs (30d)
73

Description

To Reproduce
  1. Create an Application or Compose using the Git provider with an SSH URL (git@host:org/repo) and an SSH key.
  2. Cause the clone command to fail. A reliable trigger: an SSH host whose ssh-keyscan returns non-zero (e.g. hf.co), which aborts the set -e clone script before git clone.
  3. On the Dokploy host:
    docker service logs dokploy 2>&1 | grep -A3 "BEGIN OPENSSH PRIVATE KEY"
    
  4. The configured private key is printed in plaintext inside the logged command string.
Current vs. Expected behavior

Current: when a shell command fails, the full command string is logged to the service logs. Some commands embed a private key directly in the string, so the key is written to docker service logs in plaintext.

Commands that embed a private key:

  • packages/server/src/utils/providers/git.ts:47 and :77 — SSH deploy key: echo "${sshKey.privateKey}" > /tmp/id_rsa
  • packages/server/src/services/certificate.ts:113 — TLS certificate private key: echo "${privateKey}" | base64 -d > "${keyPath}" (the serverId / remote path; the local branch uses fs.writeFileSync and is unaffected)

The command is stored and logged unredacted:

  • packages/server/src/utils/process/ExecError.tscommand is a public field and getDetailedMessage() includes it
  • packages/server/src/utils/process/execAsync.ts — the raw command is attached in execAsync (L31), execAsyncStream (L60/L93) and execAsyncRemote (L178)
  • it is then logged at execAsync.ts:91 and utils/builders/index.ts:185 via console.log(error). The same console.log(error) / console.error(error) of ExecError objects recurs across the backups/restore/notifications paths, so any command built with an embedded secret can leak the same way (e.g. DB credentials in backup/restore commands, tokens in HTTPS clone URLs).

Expected: private keys are never placed into a command string, and secrets are redacted before any command / stdout / stderr is logged.

Severity / scope

Low. Reading these logs requires privileged access to the host (docker/root), and a host-root actor can already read the same keys from Dokploy's local database — so the log exposure grants little incremental access. The practical risk is secrets propagating into forwarded log aggregators / retention systems whose read access is broader than host root. This is a secret-hygiene / defense-in-depth issue (CWE-532), not a remotely exploitable vulnerability.

Suggested fix
  1. Do not interpolate private keys into shell commands. Provision the key file out of band — write via stdin / SFTP for remote servers, or write locally then transfer — so the key never appears in a command string.
  2. Redact secrets in ExecError before storing/logging: mask content between BEGIN/END key markers and base64 blobs piped to base64 -d, in command / stdout / stderr.
  3. Avoid logging bare error objects in the deploy/build/backup paths; log a sanitized message instead.
Provide environment information
Dokploy version: 0.29.8
Host OS: Ubuntu 24.04 LTS, x86_64 (Docker Swarm, single manager)
Deploy target: remote server (Docker Compose), custom Git over SSH
Which area(s) are affected?

Application, Docker Compose, Remote server, Traefik (certificate provisioning)

Are you deploying the applications where Dokploy is installed or on a remote server?

Both — the git code path applies to local and remote; the certificate path is remote-only.

Will you send a PR to fix it?

No

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/server/src/utils/providers/git.ts, packages/server/src/services/certificate.ts, and the ExecError and execAsync files to trace how secret-bearing commands become logged. Compare local and remote paths, then check the deploy, build, backup, and restore logging mentioned in the issue. Done means private keys and other embedded secrets no longer appear in command, stdout, stderr, or service logs.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, git, typescript
Domain
backend, devops, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.