RoastMyOpsec

Vulnerabilities

.env.example vs .env on Production Origins

August 20, 2023

.env.example vs .env on production origins is two files that must not sit next to index.html. /.env (and /.env.local) is live credentials: database URLs, API secrets, APP_KEY. /.env.example is supposed to be placeholders so new developers know which names to set. Teams still copy real values into the example, or the example lists enough names to map the stack. Neither belongs in a public object store. RoastMyOpsec probes /.env and /.env.local with bounded GETs looking for signatures. It does not currently score /.env.example, does not parse dotenv into a loot list, and does not use leaked keys.

The practical difference

.env is the secret store a framework loads at boot. .env.example is documentation that hitchhiked into the static artifact. .env.backup and .env.bak are cousins. Git history of a public /.git is a third channel — see exposed .git vs .env.

A 200 on .env.example is not 'safe because it is an example.' Treat it as an information leak and deny the prefix.

How to choose what to publish

CI: fail if .env, .env.local, .env.example, or .env.* appear in a CDN artifact (keep examples in the private repo only). CDN: deny those names even if CI is perfect. Docs: describe required variables in an internal wiki, not on the marketing host. Staging hostnames that are guessable get the same deny list.

FileIntended jobPublic originTakeaway
/.env / .env.localRuntime secretsNeverScored paths on the roast
/.env.exampleDev templateNever on the CDNNot scored today; deny anyway
/.git/HEADVCSNeverSee .git vs .env
/package.jsonJS inventoryUsually noSee public package.json

When .env.example still wins (off the public origin)

It wins in a private repo so onboarding knows variable names with empty or obviously fake values. It never wins as a downloadable object on roastmyopsec.com's customers' CDNs. Pair with dump.sql if the same zip also held a database.

What the roast can prove

Signature hits on /.env and /.env.local can surface. .env.example is not a scored path. A 404 is not proof the file is gone from another prefix. Confirm in the bucket. Pair with framework debug if APP_DEBUG leaked from the same file.

Common mistakes

The first mistake is committing .env.example with yesterday's production URL still in it.

The second mistake is allowing .env* on the CDN because 'the example has no secrets.'

The third mistake is Disallow: /.env.example and calling it access control.

Free audit the URL you own

RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.

Free audit now

FAQ

Is .env.example a vulnerability?
On a public origin it is an information leak. Keep templates in the private repo. It is not the same as a live .env, but it is not harmless.
Does RoastMyOpsec fetch .env.example?
Not as a scored path today. It does probe .env and .env.local. Deny the whole .env* family at the edge.
Should I put real-looking keys in the example so it 'works'?
No. Use empty values or obvious placeholders. Never copy production strings into a template.

Sources

Related guides