Dotenv Exposure Checker
Paste your site's URL. This sends a plain GET request to five well-known dotenv filenames
(.env, .env.local, .env.production,
.env.production.local, .env.development.local) and verifies each
response against the real KEY=VALUE line shape of a dotenv file — not just an
HTTP status — before calling anything exposed. Variable values are never read, stored, or
shown anywhere by this tool — only variable names. See
why .env files end up in production for the
common causes and the fix for each. Only run this against a site you own or are authorised to
test.
Run the check
Enter a site URL, then click Check.
Report
Every path checked
| Path | Result |
|---|
Prefer a CLI, or hit a CORS wall in the browser?
Most servers don't send permissive CORS headers on arbitrary static paths, so a browser tab often cannot read a cross-origin response at all — you'll see a generic network error with no HTTP status. The CLI has no such restriction and is the one path guaranteed to complete:
node check.mjs https://example.com/ --json
Get check.mjs, probe.mjs, and analyze.mjs from the repo — exit code 1 if any path is exposed, so you can gate a deploy on it.
Common questions
Why would a production site be serving its own .env file?
Usually because a deploy step copies the whole project directory — .env included — to the web root instead of only the built output, or because a framework's static file server was pointed at the project root rather than a dedicated public/ directory. Node.js, Next.js, Laravel, Django, and Rails all read a project-root .env file by convention, so it commonly sits right next to the code the web server is meant to serve.
Does this tool show me the actual secret values?
No, never. This tool reads a response body only to check its line shape (is this KEY=VALUE formatted, like a real dotenv file) and to extract variable names — it never displays, stores, or reports a value, not even a redacted or partial one. A variable name like STRIPE_SECRET_KEY being present is already enough to know a real credential is likely exposed, without this tool ever needing to show what that credential is.
How is this different from just typing the URL into my browser?
A browser tab shows you the raw response, but many servers return their normal 200 page (a single-page app's fallback route, a themed 404) for literally any path — which can look plausible enough to misread as an exposure, or a real one might be dismissed without checking the content. This tool verifies the body actually has the real KEY=VALUE line shape of a dotenv file before calling anything exposed, and checks five well-known filenames in one run instead of one at a time. See how this compares to checking by hand.
Is it safe to point this at a URL?
This tool sends only ordinary GET requests to the five paths under the URL you name — the same requests your own browser already makes when you type one of those URLs in by hand — and it never writes or submits anything. It does not upload the URL or anything it finds to our servers when run in the browser; every request goes straight from your browser to the target. Still, only run this against a site you own or are authorised to test, the same caution you'd apply to any request tool aimed at someone else's server.
Does a clean report mean my deployment has no secrets exposed anywhere?
It means the five paths this run checked either returned a clean 401/403/404 or did not match the dotenv file shape expected for them. It does not check other common secret-exposure paths (a stray .git directory, a config.json, a backup archive), does not crawl the rest of the site, and only checks the one base URL you give it. Treat a clean report as evidence about what this run actually found, not a full audit of the deployment.