My .env file got exposed. What should I do?
If your .env file was reachable from a browser, treat every secret inside it as public knowledge — right now. The good news: you can shut the door and rotate your way back to safety in an afternoon. Here's the order to do it in.
First: don't panic, and don't delete the evidence.
An exposed .env is common and fixable. Resist the urge to just remove the file and move on — the secrets are already out, so your real job is rotation and review, not cleanup. Keep your logs intact; you'll need them.
// the 60-second version
- Block public access to the file immediately.
- Rotate every credential in the file — assume all are compromised.
- Review access logs for who fetched it, and database/API logs for misuse.
- Move secrets out of the web root for good and keep them out of git.
01Understand what just leaked
A .env file is the keyring for your whole application. When it's served as plain text, anyone who requested the URL — search-engine crawlers, automated scanners, opportunists — may now hold:
- Database credentials — host, username, password, sometimes a public port.
- Third-party API keys — payment processors, email/SMS providers, cloud storage, AI APIs. These often carry real billing exposure.
- App secrets —
APP_KEY,JWT_SECRET, session and signing keys. With these, an attacker can forge valid sessions or tokens. - SMTP / mail credentials — enough to send mail as you and pass your SPF/DKIM checks.
Assume the worst. Once a secret has been publicly reachable, you can never prove it wasn't copied. The only safe response is to rotate it, not to hope nobody looked.
02Stop the bleeding — block public access
Before rotating anything, make sure the file can't be fetched again. The exposure almost always comes from the file sitting inside a publicly served directory, or the web server handing back dotfiles.
Confirm it's reachable, then deny it. For Nginx, refuse any request for hidden files:
location ~ /\. { deny all; return 404; }
For Apache, in your virtual host or .htaccess:
<FilesMatch "^\."> Require all denied </FilesMatch>
Then verify from outside your network — request the URL again and confirm you get a 403 or 404, not the file contents.
03Rotate everything — in priority order
This is the part that actually protects you. Generate new secrets and revoke the old ones; don't just edit the file. Work roughly highest-impact first:
- Payment & billing keys (Stripe, PayPal, cloud provider keys) — these cost real money. Revoke and reissue in the provider dashboard.
- Database passwords — change the DB user's password, then update the app config. If the DB port was publicly reachable, restrict it to your app's network.
- App / signing secrets — regenerate
APP_KEY,JWT_SECRET, session keys. Note this will log everyone out and invalidate existing tokens — that's the point. - Mail & messaging — rotate SMTP passwords and provider API keys.
- Everything else — analytics, storage, webhooks, OAuth client secrets. If it was in the file, it's on the list.
Revoke, don't just replace. Many providers leave the old key working until you explicitly delete it. A new key alongside a still-valid old one solves nothing.
04Read the logs — what did they reach?
Now find out whether anyone used what they found. You're looking for two things: who fetched the file, and what they did with the keys.
Who downloaded the .env
Grep your web access logs for requests to the file. Note the IPs, timestamps, and user agents — and whether the response was a 200:
# who requested it, and did they get a 200? grep "\.env" /var/log/nginx/access.log | grep " 200 "
Whether the keys were used
- Database — check for connections from unfamiliar IPs, unusual query volume, or new/dropped tables around and after the exposure window.
- API providers — most dashboards show per-key usage and request logs. Look for spikes, calls from new regions, or activity you can't attribute.
- Mail — a sudden jump in sent volume or bounce rate is a classic sign your SMTP creds were used for spam.
- Auth — if app/JWT secrets leaked, look for logins or token use that predates your rotation but doesn't match a real user.
Write down the exposure window — from the earliest possible publish time to the moment you blocked access. That window frames everything you need to investigate.
05Make sure it can't happen again
- Move secrets out of the web root. Application config should live above the publicly served directory, never inside it.
- Keep
.envout of git. Add it to.gitignoreand commit a.env.examplewith empty values instead. - Add a deny rule by default for all dotfiles (step 2), so a future stray file isn't served either.
- Consider a secrets manager — Vault, AWS/GCP Secrets Manager, Doppler — so production secrets are never files on disk at all.
- Add monitoring for requests to sensitive paths so you hear about the next probe from your own alerts, not from a stranger.
If you handle personal data, an exposure like this may trigger breach-notification obligations (GDPR and similar). Loop in whoever owns legal/compliance once the immediate fire is out.
Was this guide useful?
These playbooks are free to read and share. If a heads-up ever saved you a bad week, you can say thanks — or jump into the other guides.