VibeSecurity

Fix

Fix: .env file publicly accessible on your website

A .env file holds database passwords, API keys and signing secrets. If a browser can download it from your domain, so can anyone, and automated crawlers request that path constantly.

By the VibeSecurity team3 min read

What this means

The finding means a request to https://yourapp.com/.env returns the file's contents instead of a 404. Every value in it must be treated as stolen: you cannot know who fetched it. Deleting the file stops new leaks but does nothing about copies already taken, which is why rotation comes first.

Why it happens

  • The web server's document root is the project folder instead of a public or build folder. This is common with hand-configured nginx, Apache or PHP hosting.
  • The .env file was placed in, or copied into, the public or static directory, which frameworks serve as-is.
  • A deploy step uploads the whole repository, dotfiles included, to static hosting or a storage bucket.
  • A Docker image copies the entire project with COPY . . and a static file server then serves the working directory.
  • An AI tool created the .env next to index.html in a simple static project, where everything in the folder is public.

How to fix it

  1. 1Rotate first. For every key, password and token in the file, create a new value at the provider and revoke the old one. Include database passwords, JWT signing secrets, payment keys and email or SMS provider keys.
  2. 2Remove the file from anywhere the web server can reach. Secrets belong in your host's environment variable settings (Vercel, Netlify, your container platform), not in a file inside the deployed site.
  3. 3Point the server's document root at the build output or public folder only.
  4. 4Block dotfiles at the server as a backstop, using the nginx rule below or your server's equivalent.
  5. 5Add .env to .gitignore and to .dockerignore.
  6. 6If the file was ever committed, purge it from git history with git filter-repo and force-push, as GitHub documents. Do this after rotation.
  7. 7Review provider dashboards and logs for use of the old keys that you do not recognise.
nginx block rule, ignore files and history purge
location ~ /\.(?!well-known) {
  deny all;
  return 404;
}

.env
.env.*
!.env.example

git filter-repo --invert-paths --path .env
git push --force --all

How to confirm the fix

Request the common paths on your own domain. Each should return 404 or 403, never 200 with file contents. Check the response body too, since some apps return the homepage with a 200 for unknown paths, which is fine. Then confirm an old key no longer works by calling the provider with it.

curl: check your own domain
for p in .env .env.local .env.production .env.backup; do
  printf '%s ' "$p"
  curl -s -o /dev/null -w '%{http_code}\n' "https://www.yourapp.com/$p"
done

curl -s https://www.yourapp.com/.env | head -n 5

Frequently asked questions

I deleted the file straight away. Do I really need to rotate everything?

Yes. You cannot tell whether it was fetched before you removed it, and access logs are often incomplete. Rotation is the only step that makes a copied secret worthless.

Can this happen on Vercel or Netlify?

Those hosts serve your build output, not your repository root, so a root .env is not normally reachable. It can still happen if the file is placed in the public or static folder or copied into the build output.

Is it safe to commit .env.example?

Yes, if it contains variable names with empty or fake values only. Check it has no real keys.

Sources

  1. 1.OWASP Secrets Management Cheat Sheet
  2. 2.GitHub: Removing sensitive data from a repository
  3. 3.Vercel: Environment variables
  4. 4.Netlify: Environment variables overview
  5. 5.Next.js: Environment variables
  6. 6.nginx: location directive