no-secrets-in-env
ENV and ARG values are baked into Docker image layers and readable with docker history. Where to put API keys and passwords instead.
On this page
ENV API_KEY=... feels like configuration, but it is storage: the value is written into the image's metadata and distributed with every push and pull. ARG is no safer — build arguments are recorded in the layer history. Anyone who can pull the image can read them back with docker history --no-trunc or docker inspect. This rule flags ENV and ARG keys that look like credentials (PASSWORD, SECRET, TOKEN, API_KEY, …) with literal values.
What the rule catches
FROM node:22-slim
ENV DATABASE_PASSWORD=sup3rs3cret
ARG NPM_TOKEN=npm_abc123Scanning this file reports:
✖ ERROR [docker-doctor/no-secrets-in-env]
Potential secret found in ENV: 'DATABASE_PASSWORD'. Secrets baked into images can be extracted easily by anyone with image access.Why it matters
An image is an artifact, not a runtime. It gets pushed to registries, cached on CI runners, copied to laptops, and mirrored — every copy carries the secret, forever, in plain text. Leaked registry credentials are one of the most common causes of cloud compromises precisely because images travel further than the people who build them expect. A secret that reaches an image layer must be treated as leaked and rotated.
How to fix it
Use Docker Secrets, build arguments passed at runtime, or environment variables at runtime instead of baking them into the image.
FROM node:22-slim
# Needed at build time? Use a BuildKit secret mount — never a layer:
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ciPick the mechanism by when the secret is needed:
- Run time (database passwords, API keys): pass at startup —
docker run -e, a Composeenv_file, or your orchestrator's secret store (Docker/Kubernetes secrets). None of these touch the image. - Build time (private registry tokens): use a BuildKit secret mount as above — the file is available during that single
RUNand leaves no trace in any layer.
If a real secret has already been committed into an image, rotate it. Deleting the image or the ENV line later does not un-publish the layers.
Rule details
- Rule key —
docker-doctor/no-secrets-in-env - Category — Security
- Default severity —
error - Applies to — Dockerfiles
Explain this rule from the CLI:
npx @docker-doctor/cli@latest rules explain docker-doctor/no-secrets-in-envChange its severity — or turn it off — in your config file:
// docker-doctor.config.ts
export default {
rules: {
"docker-doctor/no-secrets-in-env": "off",
},
};Severity affects the health score: error findings cost more points than warning, and info costs the least.