notra·
2026-08-27·4 min read·The Notra team

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:5173

The 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:

LineWhat it unlocksFirst move
SUPABASE_SERVICE_ROLE_KEY=...Full DB read/write, RLS bypassedDump every user row
JWT_SECRET=...Signs any session tokenForge an admin login
DATABASE_URL=postgres://...Direct Postgres connectionConnect from a laptop
AWS_SECRET_ACCESS_KEY=...S3, and often moreList and pull every bucket
STRIPE_SECRET_KEY=sk_live_...Live payments APIRead customers, refunds, payouts
Warning

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.

  1. Read the secret. One request, as above.
  2. Forge a login. JWT_SECRET signs sessions, so an attacker mints a token with role: admin and walks into your dashboard as you. We break this down in Forging Admin.
  3. Skip the app entirely. DATABASE_URL is a direct line to Postgres. No API, no rate limits, no logs in your app tier.
  4. Move to the cloud. AWS keys turn a database breach into an infrastructure breach: buckets, backups, sometimes IAM.
  5. 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 -5

If 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 localhost only. If you need remote access, tunnel it, do not publish it.
  • Staging never shares production credentials. Separate keys, separate database, separate blast radius.
  • .env never 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.

ShareX LinkedIn

Related

Want this run against your site?