You left your .env on the internet
Most shakedown findings are hygiene — annoying, cheap to fix, not an emergency. This is the exception. A publicly reachable .env isn't a warning sign of a breach. It is the breach.
Your .env file is the keys to the kingdom in one convenient text file: database password, API keys, your Stripe secret, JWT signing secret, SMTP credentials. It's meant to sit on your server and never, ever be handed to a browser. When it's reachable at yourdomain.com/.env, anyone who types that URL gets the whole file. No exploit, no cleverness — just a GET request.
Scanners crawl for exactly this, all day, across the entire internet. When a “researcher” emails you a screenshot of your own secrets, they didn't hack you. They typed a URL. And unlike the usual shakedown padding, this one you cannot shrug off.
How it ends up exposed
Nobody decides to publish their secrets. It happens through a handful of boring mistakes:
Serving the project root
The web server's document root is set to the folder that contains your app — and your .env sits right there next to index.php. Now every file in the project is downloadable, dotfiles included.
Committing it, then deploying the repo
The .env got committed to git (easy to do), and the deploy copies the whole repo — .git folder and all — into the webroot. Now /.git/ is browsable and someone can reconstruct your entire source, secrets included.
A static host with no dotfile rule
Plenty of setups happily serve any file you put in the public directory. If a build step copied .env into dist/, it ships to production and gets served like any other asset.
Check it in one command
You don't need a scanner to find out if you're in trouble right now. From any terminal:
If either returns your actual content, treat it as a live incident, not a to-do. Keep reading.
What to actually do
Order matters here. Rotating comes first, because the moment a secret is public you have to assume it's already copied.
- 1
Rotate every exposed secret. Assume compromised.
Every key, password, and token in that file is burned. Generate new ones — database creds, API keys, Stripe secret, JWT secret, SMTP login — and revoke the old ones. This is the step people skip, and it's the only one that actually stops the bleeding. Blocking the URL after the file's been scraped is closing the barn door. - 2
Get the file out of the webroot.
Move.envabove the public directory, or point your document root at the actual build output (e.g. apublic/ordist/folder) instead of the project root. - 3
Block dotfiles at the edge.
Add a rule so nothing starting with a dot is ever served. In nginx:location ~ /\. { deny all; }. On a CDN like Cloudflare, a WAF rule blocking/.envand/.gitpaths does the same. Belt and suspenders. - 4
Stop it recurring: .gitignore + history.
Add.envto.gitignore. If it was already committed, it's still in your git history — purge it (e.g. withgit filter-repo) and force-push, then rotate again to be safe.
Why this one isn't “just config”
We spend a lot of time telling people the shakedown email is usually bluster — a missing DMARC record dressed up as a catastrophe. This is the finding that earns the panic. The difference is simple: DMARC is a door you forgot to lock. An exposed .env is a door that's been open, with your valuables in the doorway, possibly for weeks. Fix it in that spirit — rotate first, block second, and don't assume you were the first to find it.
The good news: once it's locked down and the secrets are rotated, the scariest thing on your report becomes a 404. Nothing to screenshot, nothing to sell you.
Want to know if your .env, .git, or anything else is exposed right now? Scan in about 20 seconds.