The .env File That Ends Companies
A staging box nobody remembers
Every company has one. A staging, dev, or demo subdomain that someone spun up in a hurry, pointed at a real database "just for testing," and never took down. It still runs the framework dev server. It still holds a copy of .env. And it is one HTTP request away from anyone who looks.
This is not a theoretical class of bug. It is the single most reliable way an attacker takes a target from "outside" to "game over," because a .env file is not one secret. It is the master key ring.
The one request that opens the door
Modern front-end tooling ships a dev server that can read your filesystem on purpose. Vite exposes a /@fs/ route so the browser can import files outside the project root. There is a guard, server.fs.deny, meant to block sensitive paths like .env. It has been bypassed more than once.
A representative probe against an exposed Vite dev server:
GET /@fs/home/deploy/app/.env?import&raw?? HTTP/1.1
Host: staging.yourco.com:5173The trailing query trick (?import&raw??) sidesteps the deny list on unpatched versions, and the server hands back the raw file. No auth. No exploit payload. Just a path and one question mark too many.
The lower-tech version is even more common: a misconfigured Nginx or Apache root that serves the whole app directory, so GET /.env returns it directly. Same outcome, less cleverness.
What is actually in that file
Here is why one file ends companies. A typical .env on a real app:
| Line | What it unlocks | First move |
|---|---|---|
SUPABASE_SERVICE_ROLE_KEY=... | Full DB read/write, RLS bypassed | Dump every user row |
JWT_SECRET=... | Signs any session token | Forge an admin login |
DATABASE_URL=postgres://... | Direct Postgres connection | Connect from a laptop |
AWS_SECRET_ACCESS_KEY=... | S3, and often more | List and pull every bucket |
STRIPE_SECRET_KEY=sk_live_... | Live payments API | Read customers, refunds, payouts |
A dev server is a developer tool. It has never been safe to expose to the internet, patched or not. If a curl -I from outside your network gets a 200 on port 5173, 3000, or 8080, treat it as an incident, not a to-do.
The kill-chain, step by step
The keys do not sit there quietly. They compose.
- Read the secret. One request, as above.
- Forge a login.
JWT_SECRETsigns sessions, so an attacker mints a token withrole: adminand walks into your dashboard as you. We break this down in Forging Admin. - Skip the app entirely.
DATABASE_URLis a direct line to Postgres. No API, no rate limits, no logs in your app tier. - Move to the cloud. AWS keys turn a database breach into an infrastructure breach: buckets, backups, sometimes IAM.
- Follow the money.
sk_live_reads your customer list and payout history.
The gap between step 1 and "attacker is you" is often minutes.
How to check yours in five minutes
Non-destructive. Run these from a network that is not your office.
# 1. Is a dev/staging host reachable at all?
for p in 3000 5173 8080; do
curl -sS -m 5 -o /dev/null -w "%{http_code} :$p\n" http://staging.yourco.com:$p/
done
# 2. Does the web root leak dotfiles?
curl -sS -m 5 -i https://staging.yourco.com/.env | head -20
# 3. Vite fs.deny exposure (read-only probe)
curl -sS -m 5 'https://staging.yourco.com:5173/@fs/home/deploy/app/.env?import&raw??' | head -5If any of these returns file contents, or a 200 where you expected a refusal, you have found the thing.
The fix is boring, which is the point
- Dev servers bind to
localhostonly. If you need remote access, tunnel it, do not publish it. - Staging never shares production credentials. Separate keys, separate database, separate blast radius.
.envnever lives inside a web-served directory. Verify with the checks above, do not assume.- Rotate everything the moment a leak is even plausible. A secret that was public for an hour is a public secret forever.
Most teams do not miss this because they are careless. They miss it because a scanner pointed at production comes back clean, and the forgotten box on a different subdomain was never in scope. That blind spot is exactly what we argue about in Why Your Scanner Lies, and it is why breadth of surface matters as much as depth of test.
Point Notra at your domain and it maps the hosts you forgot you had, then verifies whether any of them leak a .env before someone else checks. Run a free scorecard, or read more field notes on the blog.