highSecrets and API keys
Secret Baked Into the Image
A credential is stored in an image layer.
Why it matters
Image layers are archives, and ENV values are plain text in the image metadata: `docker history` shows them. Supplying the secret at run time keeps the image shareable and lets you rotate the value without a rebuild.
What it looks like
This is the shape of code that triggers the rule. AI tools produce it because it works, and nothing tells them it is unsafe.
ENV with a real-looking key
FROM node:20-alpine
ENV OPENAI_API_KEY=sk-proj-abcdefghijklmnop1234567890The smallest fix
minimal patch
# Remove the ENV/ARG line and the COPY of .env, then pass the value at run time:
docker run --env-file .env <image>
# or in compose:
services:
api:
env_file: .envThe better fix
If you have a few more minutes, this is the approach that holds up as the app grows.
safe alternative
# For values needed only during the build (private registry tokens),
# use BuildKit secrets so they never land in a layer:
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci
# Add .env, *.pem and *.key to .dockerignore as well.Let your AI tool fix it
When the scanner finds this in your project, it fills in the file and line for you. This is the prompt it gives you to paste into Claude Code, Cursor or whatever you use.
In [the file] at line [the line number] a secret is baked into the image: [the flagged code]. Remove it from the Dockerfile, pass it at run time through the environment or an env_file, use a BuildKit secret mount if the build itself needs it, add the file to .dockerignore, and rotate the exposed value.
How to check the fix worked
1. Run `docker history <image>` and confirm no secret values appear. 2. Start the container with the environment provided and confirm the app can read the value.