Skip to content
All guides

Is your .env file or .git folder public? How to check and fix it

By Obscura Security · Updated · nginx, Next.js, Vite, Docker

Short answer

If https://yoursite.com/.env or https://yoursite.com/.git/HEAD returns real content instead of a 404, anyone can download your secrets or your whole source history. Serve only your build output folder, add deny rules for dotfiles and backup files, then rotate every secret that was reachable.

Some files exist to run your app, not to be downloaded: .env holds your passwords and API keys, .git/ holds your project’s full history, and backups and source maps hold code. If your web server can reach them, so can everyone else.

Why this happens

  • The site is deployed by copying the whole project folder into the web root with FTP, scp or rsync, so .env and .git go along.
  • A Docker image uses COPY . . and serves the result, with no .dockerignore.
  • A web server such as nginx has its root set to the project folder instead of the build output folder.
  • A .env, .sql dump or backup.zip was put into a public/ or static/ folder, and everything in that folder is served as-is.
  • A quick fix left config.php.bak or database.sql on the server.

Automated scanners request these paths on public sites constantly, so assume a file that was reachable has been found.

How to check your own app

Do this against your own site only.

  1. Request the usual suspects. A correct site returns 404 or 403 for each:
curl -s -o /dev/null -w "%{http_code}  /.env\n"        https://YOUR-SITE.com/.env
curl -s -o /dev/null -w "%{http_code}  /.env.local\n"  https://YOUR-SITE.com/.env.local
curl -s -o /dev/null -w "%{http_code}  /.git/config\n" https://YOUR-SITE.com/.git/config
  1. Check the content, not just the status. Many single-page apps answer 200 with their homepage for any path:
curl -s https://YOUR-SITE.com/.env | head
curl -s https://YOUR-SITE.com/.git/HEAD

If the first shows KEY=value lines, or the second shows ref: refs/heads/main, the file is public.

  1. Try other common names: /backup.zip, /db.sql, /dump.sql, /config.php.bak, /.env.production.
  2. Check for source maps. In the browser’s Network tab, find one of your JavaScript files and add .map to its URL. If you get a large JSON file with sourcesContent in it, your source code is public.

The fix

1. Serve only the build output

Point the web server at the folder containing built files, such as dist, build or out, never the project root.

server {
    listen 80;
    server_name yoursite.com;
    root /var/www/myapp/dist;   # build output only
}

On Vercel, Netlify and Cloudflare Pages, set your environment variables in the project’s dashboard, not in files, and don’t put .env files inside public/ or static/.

2. Add deny rules as a second layer

In nginx, refuse dotfiles and common backup extensions. Keep /.well-known/ working, since certificate renewal can need it.

location ~ /\.(?!well-known) {
    deny all;
}

location ~* \.(bak|old|orig|sql|sqlite|log|swp|map|env)$ {
    deny all;
}

location ~ ~$ {
    deny all;
}

Reload with sudo nginx -t && sudo systemctl reload nginx. Then repeat the curl checks. If you use location / blocks with their own rules, make sure these still win. A regex location beats a plain prefix location.

3. Keep the files out of the deployment

  • Add .env* and .git to .dockerignore.
  • Add .env* to .gitignore. If .env was ever committed, git rm --cached .env stops tracking it, but it stays in history.
  • Delete leftover .bak, .sql and .zip files from the server.

4. Turn off production source maps

Next.js leaves browser source maps off unless you set productionBrowserSourceMaps: true. Vite’s build.sourcemap defaults to false. Create React App generates them unless you set GENERATE_SOURCEMAP=false. If you upload maps to an error-tracking service, upload them there and don’t publish them.

5. Rotate everything that was reachable

This step matters most. Treat every value in an exposed .env as leaked: database passwords, Supabase service role key, Stripe secret keys, OpenAI or Anthropic keys, JWT secrets, email provider keys. Generate new ones, update your hosting, and revoke the old ones.

If .git/ was exposed, the whole history was downloadable, including secrets you deleted long ago. Rotate those too. Removing a secret from history with git filter-repo is worthwhile for tidiness but doesn’t undo a leak, because the old copy has already left.

Then check your access log for earlier requests:

grep -E 'GET /(\.env|\.git)' /var/log/nginx/access.log | grep ' 200 '

Mistakes to avoid

  • Rotating only some keys. If you can’t tell which were in the file at the time, rotate all of them.
  • Checking the status code only. 200 on an SPA may be harmless, and 403 on one path doesn’t mean another path is blocked.
  • Putting secrets in NEXT_PUBLIC_ or VITE_ variables. Those are built into the JavaScript that every visitor downloads. See secret API key in frontend.
  • Fixing the web server but leaving the secret. Deny rules stop future downloads. They don’t undo past ones.

Common questions

I deleted the .env file from the server. Am I safe now?
The file is no longer served, but anything that was reachable should be treated as compromised, because automated scanners request these paths on public sites all the time. Rotate every secret that was in the file.
My site returns 200 for /.env but shows my homepage. Is that a problem?
Probably not. Single-page apps often return index.html for any unknown path. What matters is the content. If the response is your homepage HTML, nothing is leaked. If it contains lines like KEY=value, it is.
Are source maps a security problem?
They expose your original source code, which makes it easier for someone to find endpoints and any key that ended up in the frontend. They aren't a secret leak by themselves, but there is little reason to publish them in production.
How do I know if someone already downloaded my .env?
Check your web server's access log for requests to /.env or /.git/ that returned status 200. If you see any, assume the contents were taken. If your host gives you no logs, assume the worst and rotate.

Written by Obscura Security, an Australian practice that checks web apps for problems like this one. If you want a second pair of eyes on yours, email [email protected].