exposure · July 10, 2026 · 5 min read
Exposed .env and .git Files: The #1 Way Websites Leak Secrets
An exposed .env or .git folder hands attackers your database credentials and API keys. Learn how it happens, how to check, and how to fix it.
Every day, automated scanners sweep the public internet requesting the same handful of paths on every domain they find: /.env, /.git/config, /backup.sql. They are not targeting you specifically — they are targeting everyone, and they only need one hit. If one of those files is reachable on your site, assume it has already been downloaded.
What these files actually contain
A .env file is where modern apps keep configuration secrets, one per line:
DATABASE_URL=postgresql://user:password@host:5432/app
OPENAI_API_KEY=...
STRIPE_SECRET_KEY=...
JWT_SECRET=...
SMTP_PASSWORD=...It exists precisely so secrets stay out of your code — which means that if the file itself becomes downloadable, everything sensitive about your app is in one convenient place.
A .gitfolder is the version-control database for your project. If it is reachable over HTTP, anyone can reconstruct your entire source code: every file, every commit, including secrets that were committed once and “deleted” later. Even .git/config alone can reveal private repository URLs and, in older setups, embedded credentials.
How these files end up public
Nobody uploads a .env file on purpose. It happens through boring mechanics:
- The web root is the project root. The server is configured to serve the whole project folder instead of a
public/or build-output directory, so dotfiles ship along with your HTML. - Deploying by copying. Running
git clonestraight into the web directory, or pushing the full project folder over FTP or rsync, brings.gitand.envalong for the ride. - Deploy artifacts. Build scripts, backup jobs, and one-off exports (
backup.zip,dump.sql) get written into a served directory and forgotten. - Copied and scaffolded projects. Templates and AI-generated projects often include example env files that later get filled with real values. If you built your app with Cursor, Lovable, Bolt, or v0, this deserves an explicit check — see our guide for AI-built apps.
Why one exposed .env is game over
This is the rare case where a single finding equals full compromise:
- Database credentials let someone read or modify every user record directly, without touching your app at all.
- API keys (Stripe, OpenAI, AWS, email) let someone spend your money, send mail as you, or move into your cloud account. Keys also leak through a second route worth checking: your JavaScript bundle.
- JWT or session secrets let someone forge a valid login for any user, including admins.
And because the file gets fetched by bots rather than a curious person, exposure time is measured in minutes, not months.
The rest of the exposure family
.env and .git are the headliners, but the same misconfiguration exposes a whole family:
backup.sql,dump.sql,backup.zip— full copies of your database or sitephpinfo.php— server configuration, file paths, and loaded modules/server-status— a live feed of requests hitting your Apache server.DS_Store— macOS folder metadata that reveals file names you never linked to- IDE files like
.vscode/sftp.jsonor.idea/— sometimes containing deployment credentials - Source maps (
.js.map) — your readable original source, shipped next to the minified bundle
If your backend is Supabase, the stakes stack: an exposed .env usually contains the service_role key, which bypasses Row Level Security entirely.
How to check your own site
You can test this in one minute with curl or a browser:
curl -i https://yourdomain.com/.env
curl -i https://yourdomain.com/.git/HEAD
curl -i https://yourdomain.com/.git/config
curl -i https://yourdomain.com/backup.sqlYou want a 404 or 403 with no file contents. Two things to watch:
- A real
.git/HEADstarts withref: refs/heads/, and a real.envhasKEY=valuelines. If you see those, the exposure is live. - Single-page apps often answer 200 for every pathwith the app’s HTML shell (a “soft 404”). A 200 status alone doesn’t prove exposure — the response body has to actually match the file.
How to fix it
- Serve a build directory, not the project. Your web root should contain only what the browser needs.
- Block sensitive paths at the server or CDN. For nginx:
On Cloudflare or another CDN, add a rule blockinglocation ~ /\.(?!well-known) { deny all; }/.env*,/.git/*, and backup extensions before requests ever reach your server. - Delete artifacts — backups, dumps,
phpinfo.php— from anywhere web-reachable. - Rotate every secret that was exposed. This is the step people skip. Removing the file does not un-download it: change the database password, reissue every API key, rotate JWT secrets.
- Keep secrets out of git going forward:
.env .env.* !.env.example *.sql *.zip .DS_Store
How BoringSec checks this
BoringSec’s exposure scanner is one of 24 runtime modules. It probes 34 sensitive paths plus directory listing and robots.txt — 36 checks in total. .git/config, .git/HEAD, .env, .env.local, and .env.production are rated critical, and any confirmed critical finding caps your Security Score at 30 — an F.
Every hit is confirmed with content-signature matching: the response body has to look like the real file, so SPA soft-404s don’t create false positives. That’s part of our evidence-first design — critical and high findings without captured proof are automatically downgraded to medium, because we don’t sell fear. Every finding cites the standard behind it (OWASP, CWE, RFC, MDN); the full approach is on our methodology page.
FAQ
Is an exposed .git folder dangerous if my repo contains no secrets?
I removed the exposed .env file. Am I safe now?
Do I need to check this on Vercel or Netlify?
Keep reading
Check your site now
One scan applies the relevant checks from 20 base URL modules plus 3 verified-owner background engines. Free, no signup, with base results appearing first.
Scan your site free