Safeguard
Cloud Security•

.env Files in Docker Images: What Flare Found and How to Stop It

Flare found 10,456 Docker Hub images with exposed keys in November 2025, and .env files were a common cause. Check your images, fix the build, and rotate what leaked.

Safeguard Security Team
4 min read

On 10 December 2025 the security firm Flare published a scan of Docker Hub images uploaded in November 2025. It found 10,456 container images with one or more exposed keys. After filtering to high and critical findings, 205 namespaces remained, and 101 of them were tied to identifiable companies, including one Fortune 500 firm.

The report says the cause is mundane. Developers keep credentials in a local .env file. If the whole project directory is copied into a Docker build, that file ends up inside the image for anyone who pulls it. Libraries such as dotenv and python-dotenv make the file convenient, and a careless COPY . . makes it public.

What's affected

From Flare's numbers:

  • About 42% of the leaking images held five or more secrets.
  • Almost 4,000 AI provider keys were exposed.
  • Named examples included GitHub, npm, PyPI and AWS credentials, plus keys for OpenAI, Anthropic, Hugging Face, Gemini and Groq.
  • About 25% of developers removed the leaked secret within one to two days, but the report says credentials were often not revoked. It states that 75% of exposed organizations failed to revoke or rotate their keys.
  • Personal and contractor registries were part of the picture. One freelancer account had 70 repositories, and a bank's chief architect had over 430 public images in a registry.

This is not only a public registry problem. A private registry image is one stolen pull credential away from the same exposure.

How to check if you're exposed

Inspect an image the way a stranger would. These commands work on any image you can pull.

# Is an .env or key file in the filesystem?
docker create --name probe myorg/app:latest
docker cp probe:/app/.env ./probe.env && echo "FOUND .env"
docker rm probe

# Do build instructions carry values?
docker history --no-trunc myorg/app:latest | grep -iE 'token|secret|password|key'

Then check the repository side for the patterns that cause it:

grep -nE '^(COPY|ADD) +\. ' Dockerfile
test -f .dockerignore && grep -nE '\.env|\.pem|\.aws' .dockerignore || echo "no .dockerignore rules"

For a wider pass, run a scan across your images and your repositories. The free Safeguard dependency scan checks package manifests in the browser, but it will not find files baked into layers, so use a secret scanner for that.

What to do now

  1. Treat any key found in an image as compromised. Revoke or rotate it first. Flare's data shows removing it from the image is not enough.
  2. Add a .dockerignore before anything else:
.env
.env.*
*.pem
*.key
.aws
.git
  1. Stop copying the whole directory. Copy named paths instead of COPY . ..
  2. Do not pass secrets with ARG or ENV. Docker's documentation says build arguments and environment variables persist in the final image. Use a secret mount, which exists only for the duration of the instruction that uses it:
RUN --mount=type=secret,id=npm_token,env=NPM_TOKEN npm ci
docker build --secret id=npm_token,env=NPM_TOKEN .
  1. Inject runtime secrets when the container starts, from your orchestrator or a secrets manager, not at build time.
  2. Prefer short-lived credentials. For cloud access from CI, use OIDC federation instead of storing a key, as in our GitHub OIDC guide.
  3. Scan images in CI before pushing, and scan registries you do not control, including personal and contractor accounts.

How to avoid this trap

  • Ignore files by default. A .dockerignore with .env.* removes the most common cause Flare names.
  • Build secrets are not image content. --mount=type=secret is built for this and leaves nothing in a layer.
  • Rotate on exposure, always. The 75% figure shows the real failure is the step after the cleanup.
  • Own your registries. Contractor accounts sit outside corporate oversight. Put image publishing behind your organization.
  • One image, one purpose. Keep local config out of the project root that the build sees.

Try it yourself

Take your most recent production image, run the three inspection commands above, and write down what you find. Then scan it.

Click through it at your own pace, or open it full screen.

Quick check

Why are ARG and ENV the wrong place for a build secret?

Docker's documentation says build arguments and environment variables persist in the final image, so anyone with the image can read them.

You deleted the .env file and pushed a new image tag. Are you done?

No. The old image and its layers may already be copied, and the key must be revoked or rotated.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.