Vulnerabilities
Soft 404 vs Hard 404 for Sensitive Paths
December 1, 2025
Soft 404 vs hard 404 for sensitive paths is why status codes lie. A hard 404 (or 403/401) with a tiny generic body usually means the file is not there or is denied. A soft 404 is a 200 that returns your marketing HTML for every unknown path — including /.git/HEAD and /.env. Scanners that only check the status line will pass or fail the wrong test. RoastMyOpsec looks for file-specific signatures and soft-404 behavior on bounded path probes. Deny VCS and env paths at the CDN even when the SPA would have rendered a homepage.
The practical difference
A hard 404 is an honest miss: the origin or edge says not found. A 403 is an honest deny. A 200 with application/json that is actually a key-value env dump is an incident. A 200 with text/html that is your React shell is a routing default, not a treasure chest — unless the body also matches a real file signature.
Redirect-to-home on every unknown path is the same class of confusion as a soft 404.
How to choose what to configure
At the edge, deny or 404 well-known sensitive prefixes before they hit the SPA. Let the app 200 only for real document routes. Do not use 'always index.html' for /.git, /.env, /backup.zip, or *.map if those files must never exist in production.
| Response | Likely meaning | OPSEC move | Takeaway |
|---|---|---|---|
| 404 + small generic body | Not present or blocked | Still deny at edge forever | Honest miss |
| 200 + SPA HTML | Soft 404 / client router | Exclude sensitive prefixes from the rewrite | Status 200 is not a file |
| 200 + env/git signature | Real leak | Rotate, deny, incident process | See .git vs .env guide |
| 301/302 to / | Catch-all redirect | Stop treating it as 404 | Same confusion as a soft 404 |
When a 'clean' scan still needs an edge rule
A marketing SPA can look clean because every probe returns the shell. That is not the same as a WAF deny. Add explicit denies so a future mis-deploy cannot publish .git next to index.html.
Preview deployments that skip those rules are how 'prod is fine' still leaks.
Common mistakes
The first mistake is trusting curl -I status codes alone.
The second mistake is a single rewrite-to-index for the entire hostname.
The third mistake is blocking in robots.txt and not at the CDN.
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 nowFAQ
- Does a 200 on /.env always mean the file leaked?
- No. On many SPAs it is the homepage HTML. Confirm Content-Type and whether the body looks like env keys versus your app shell.
- Should I still block /.git if I get a soft 404?
- Yes. Edge deny is cheap and survives the next accidental upload.
- How does RoastMyOpsec tell them apart?
- Bounded GETs plus content signatures and soft-404 checks — not status codes alone. No recursive git dump.
Sources
Related guides
Vulnerabilities
Exposed .git vs .env on Production WebsitesVulnerabilities
Directory Listing vs 403 for Backup and Static FoldersVulnerabilities
Production Source Maps: When They Leak Source and Secrets