RoastMyOpsec

Vulnerabilities

Exposed .git vs .env on Production Websites

September 14, 2023

Exposed .git vs .env on production is not a ranking of which leak is 'less bad.' A reachable .env is usually a credential dump — API keys, database URLs, signing secrets. A reachable .git tree is a source and history dump that often contains those same secrets plus every old one. Both belong behind a deny at the CDN or origin, not behind hope. RoastMyOpsec probes well-known paths with bounded GETs, then checks for real file signatures versus soft-404 HTML that pretends the file is missing.

The practical difference

.env files are configuration. When they are public, rotation is the first job because the values are live secrets until proven otherwise.

.git directories are process. When they are public, you assume source, commit history, and leftover credentials may be recoverable. Blocking the path is not the whole fix if the repo already left the building.

Backups, .DS_Store, phpinfo, and source maps are cousins of the same class: the production document root is not a home folder.

How to choose what to fix first

If .env is reachable, rotate everything it named, then deny the path. If .git is reachable, take the site offline-from-VCS at the edge, rotate secrets found in history you control, and confirm CI is not publishing the repo as a static folder.

Do not 'hide' these paths only in robots.txt. That advertises them. Access control belongs at the server and CDN.

ArtifactTypical blast radiusFirst responseTakeaway
.env / .env.localLive secrets for APIs, DB, signingRotate, deny, audit logsTreat as a credential incident
.git/HEAD and objectsSource + history + old secretsDeny at edge, rotate, review historyHistory is part of the leak
zip / sql / bak dumpsData and config souvenirsRemove from origin, deny patternsBackups do not belong next to index.html
package.json on a private appDependency and script intelDecide if the app should be public at allNot always a secret, still a map

When a '404' is not a 404

Some frameworks serve the SPA shell for every path. A 200 with your homepage HTML is a soft 404. Scanners that only check status codes will lie. RoastMyOpsec looks for file-specific signatures and soft-404 behavior so a marketing SPA does not get a fake pass.

Your own check on a site you own should confirm Content-Type and body shape, not just the status line.

Common mistakes

The first mistake is deploying the git working copy as the web root.

The second mistake is copying .env.example to .env and leaving it in public/.

The third mistake is blocking /.git in one CDN rule and forgetting preview deployments.

Defensive scan, then edge deny

Run a RoastMyOpsec free audit on a URL you own. Sensitive-path checks are part of the unlocked pack. If something answers like a real file, fix the edge first, rotate second, then re-scan.

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 an exposed .git worse than an exposed .env?
Both are incident-class. .env is usually live credentials. .git is source plus history, which often includes credentials from older commits. Fix both; do not debate the trophy.
Does a 404 on /.git mean I am safe?
Not by itself. Soft-404s and redirects to home can mask a miss or a hit. Confirm the body is not your app shell, and deny the path at the edge anyway.
Will RoastMyOpsec download my git history?
No. Checks are bounded GETs to well-known paths looking for signatures. There is no recursive dump and no exploit payload.

Sources

Related guides