Skip to content

no-plaintext-secrets

API keys and passwords written literally in a Compose file end up in version control. Where to put Compose secrets instead: interpolation, env_file, or secrets.

On this page

A Compose file is code: it gets committed, reviewed, forked, and pushed to template registries. A literal OPENAI_API_KEY: sk-… in environment: therefore publishes the credential to everyone with repo access, and to every clone, mirror, and backup, forever. This rule flags environment entries (map or list syntax) whose key looks like a credential (PASSWORD, SECRET, TOKEN, API_KEY, …) and whose value is a literal rather than a ${VAR} interpolation.

What the rule catches

compose.yaml — credentials committed in plain text
services:
  agent:
    image: my-agent:1.2.0
    environment:
      OPENAI_API_KEY: sk-proj-abc123
      DB_PASSWORD: hunter2

Scanning this file reports:

⚠ WARN [docker-doctor/no-plaintext-secrets]
  Potential secret in service 'agent' environment: 'OPENAI_API_KEY'. A literal value here lives in version control in plain text.

Why it matters

Committed credentials are one of the most common real-world breach vectors, and compose files travel further than people expect: they get pasted into issues, copied into starter templates, and pushed to public forks. Agent stacks concentrate the risk, since one file often holds keys for a model provider, a search API, and a database at once. The rule only inspects the key name, so it cannot tell a real key from a placeholder; treat a hit on a placeholder as a prompt to switch to interpolation before the placeholder becomes real.

How to fix it

Move the value to an env_file kept out of version control, interpolate it from the host environment (${VAR}), or use Compose secrets:.

compose.yaml — values resolved outside the file
services:
  agent:
    image: my-agent:1.2.0
    environment:
      # resolved from the host environment / .env at compose up time
      OPENAI_API_KEY: ${OPENAI_API_KEY}
    env_file:
      - .env.local # gitignored

Pick the mechanism by how sensitive the value is:

  • ${VAR} interpolation: Compose resolves it from the host environment or a .env file at compose up time; the compose file carries only the reference.
  • env_file: point it at a gitignored file to keep whole blocks of configuration out of version control.
  • Compose secrets: mounts the value as a file rather than an environment variable, which also keeps it out of docker inspect output and crash dumps.

If a real credential has already been committed, rotate it. Removing the line only hides it from the working tree, not from git history.

Rule details

  • Rule keydocker-doctor/no-plaintext-secrets
  • Category — Compose
  • Default severitywarning
  • Applies to — Docker Compose files

Explain this rule from the CLI:

npx @docker-doctor/cli@latest rules explain docker-doctor/no-plaintext-secrets

Change its severity — or turn it off — in your config file:

// docker-doctor.config.ts
export default {
  rules: {
    "docker-doctor/no-plaintext-secrets": "off",
  },
};

Severity affects the health score: error findings cost more points than warning, and info costs the least.