Methodology, ethics & privacy

How ExposureCheck works

ExposureCheck looks at what your live site actually serves to the public internet and flags the things that leak secrets — a published source map, a readable .env, an exposed .git folder, an API key baked into your front-end bundle. This page explains exactly how the scan works, what it checks, the rules for using it responsibly, what it does with your data, and what to do the moment you find a real exposure.

Part of the Copper Bay Labs ship-safety suite

ExposureCheck is one of three free, client-side checks for people shipping vibe-coded and indie apps. Each looks at a different blast radius — together they answer “did I just ship something that gets me sued, popped, or scraped?”

How the scan works

ExposureCheck runs entirely in your browser — there is no ExposureCheck backend. To inspect a live URL, though, your browser can’t read another site’s files directly: the browser’s same-origin policy blocks a page on exposurecheck from reading raw responses from yoursite.com. So the tool offers two modes:

  1. URL mode (via a public CORS proxy). You give it a URL. ExposureCheck requests that page — and a short list of well-known sensitive paths next to it — through a public, open CORS proxy that adds the cross-origin headers your browser needs. The fetched text comes back into your tab, and all of the actual detection (regex matching, parsing, severity) runs locally on it. Only publicly-served paths are ever requested.
  2. Paste mode (fully offline). Don’t want anything proxied? View source on your own page (or open your built bundle / a suspect file), copy the text, and paste it straight into ExposureCheck. In this mode nothing touches the network at all — it behaves exactly like LeakCheck, scanning the text right there in the tab.
The detection is the same in both modes. The proxy only solves “how do I get the bytes your live site serves into the browser.” Once the text is in the tab, ExposureCheck’s pattern engine — the same masked, textContent-safe detector family that powers LeakCheck — does all the work locally.

What ExposureCheck checks

ExposureCheck fetches your page and a handful of conventional sensitive paths, then scans the responses. Severity reflects how dangerous the exposure typically is — a readable .env or live secret key is Critical, a source map or exposed repo is High, a leaky header or risky path is Medium, and informational signals are Low.

CheckWhat it looks forSeverity
Exposed .env fileA readable /.env (or .env.local, .env.production) served as plain text with keys inside.Critical
Exposed .git directoryA reachable /.git/config or /.git/HEAD — the whole repo (and its history of secrets) can be reconstructed.Critical
Secret keys in served filesLive API keys, tokens, and private keys (AWS, Stripe sk_live_, OpenAI/Anthropic, GitHub, PEM blocks) in the HTML or JS your site serves.Critical
Published source maps//# sourceMappingURL= pointing at a reachable .map that reveals your original, un-minified source.High
Private keys / credential dumps-----BEGIN … PRIVATE KEY----- blocks or database URIs with inline credentials in any served file.High
Backup & dotfile leaksReachable .env.bak, config.json, .DS_Store, .htpasswd, /backup.zip, editor swap files.High
Server-side keys in front-endSecret-side credentials shipped to the browser (e.g. a service-role key or STRIPE_SECRET in client JS) instead of a public/anon key.High
Information-leaking headersServer: / X-Powered-By revealing exact stack versions; verbose error pages exposing stack traces or paths.Medium
Risky exposed pathsReachable /admin, /.well-known misconfig, /phpinfo, debug endpoints left enabled.Medium
Public client keys (informational)Publishable / anon keys (pk_live_, public Firebase config) that are meant to be public but flag the area for review.Low

The exact check set evolves; treat this table as representative, not exhaustive. Severities are defaults reflecting typical blast radius, not your specific setup.

Source maps, exposed .env, and exposed .git

Three of these deserve their own explanation, because they’re the ones people are most surprised to learn about.

Published source maps

When your build tool minifies JavaScript, it can also emit a .map file and append a comment like //# sourceMappingURL=app.js.map to the bundle. That map is for debugging — but if it’s deployed and reachable, anyone can download it and reconstruct your original source: variable names, comments, file structure, and any secret or internal logic that was sitting in the code before minification “hid” it. Minification is not security. ExposureCheck flags a source map that’s actually fetchable so you can stop publishing it (or strip the sourceMappingURL comment) in production.

Exposed .env

A .env file holds exactly the things that must never be public — database passwords, API secret keys, signing secrets. It’s supposed to stay on the server and be read at runtime, never served to a browser. But a misconfigured static host or webroot will sometimes serve /.env as plain text to anyone who asks. Bots scan for this constantly. If ExposureCheck can fetch your .env over HTTP, so can an attacker — treat every value in it as already compromised.

Exposed .git directory

If you deployed by copying your whole project folder (including the hidden .git directory) to the webroot, the server may be serving /.git/. From files like /.git/config and /.git/HEAD, an attacker can clone your entire repository and its full commit history — including any secret you ever committed and later “removed.” ExposureCheck checks whether those tell-tale paths respond, because a reachable .git is one of the highest-value leaks on the web.

Ethics & authorized use

Only scan sites you own or have explicit permission to test. ExposureCheck is a defensive self-check — a way to look at your own deployment the way the public already can. It is not a penetration-testing tool, and it must not be pointed at someone else’s site.

We mean this literally, and the design backs it up:

  • It only requests publicly-served paths. ExposureCheck performs ordinary, unauthenticated GET requests for conventional file locations — the exact same requests your browser makes when it loads a page. It does not log in, brute-force, fuzz, send payloads, attempt exploits, or try to access anything that isn’t already being served to the open internet.
  • It’s a self-check, not an attack. The whole point is to show you what your own site is already handing out, so you can close the gap before someone with worse intentions finds it. Run it on your domain, on staging, on a client’s site you’ve been hired to secure — not on a stranger’s.
  • Permission is your responsibility. Scanning infrastructure you don’t own or aren’t authorized to test can be unlawful in your jurisdiction regardless of how gentle the requests are. By using URL mode you confirm you have the right to test the target. When in doubt, use paste mode on output you’ve viewed yourself.

Privacy & the public proxy

ExposureCheck stores nothing. There is no account, no database, no analytics on your input, no logging of what you scan. Results live only in the current tab and vanish on reload. But because URL mode has to fetch a cross-origin site, we want to be completely straight with you about the one network hop involved:

  • Paste mode is fully local. Nothing leaves your browser — identical to LeakCheck. If privacy is paramount, prefer this mode.
  • URL mode routes the target through a public CORS proxy. To read your live site’s files, your browser sends the target URL (and the sensitive paths it derives from it) to a third-party open proxy that re-requests them with cross-origin headers. That means the proxy operator can see which URL you asked it to fetch. We disclose this openly. We don’t send your input anywhere ourselves, and the actual secret-detection runs locally on the returned text — but the fetch itself is not private from the proxy.
  • The scan results stay in your tab. Whatever ExposureCheck finds — the masked matches, the severities — is rendered locally and never transmitted. Like LeakCheck, every detected secret is masked (first/last few characters only) before it ever touches the screen, so a screenshot or screen-share doesn’t releak the very thing you’re checking for.
The honest trade-off. URL mode is convenient but passes the target through a public proxy you don’t control; paste mode is completely private but you fetch the bytes yourself. Pick the one that matches how sensitive the target is.

This is a heuristic self-check — not a full security audit

Important: ExposureCheck is a fast heuristic scanner of publicly-served content, not a security guarantee, certification, or audit. A clean result does not mean your site is secure, and a flagged result does not always mean a real exposure.

Like every pattern-based scanner it can produce both kinds of error:

  • False negatives. It only sees the handful of paths it checks and the responses it can fetch. Secrets behind auth, in unusual locations, in formats it doesn’t recognize, or blocked by the proxy can slip past unflagged.
  • False positives. Example keys, public-by-design tokens, hashes, and test fixtures can look like real exposures when they aren’t.

Use ExposureCheck as a quick first pass on your deployment, not the final word. A real audit considers your architecture, server config, dependencies, access controls, and threat model — none of which a surface scan can see. If you need that level of assurance, talk to Copper Bay Labs.

I found something exposed — fix it now

If a real exposure is confirmed, assume it’s already been found by a bot and act fast. Work the checklist top to bottom:

  1. Rotate every exposed credential immediately. Go to each provider’s dashboard and revoke or regenerate any key, token, or password that was reachable. Rotation is the only action that actually stops abuse — removing the file does not undo the exposure that already happened.
  2. Remove the file from the deploy. Take the leaking artifact out of your published output entirely — the .env, the .git directory, the source map, the backup zip. It should never have been in the webroot.
  3. Move secrets to env vars / a secret manager. Load credentials at runtime from environment variables or a real secret manager (AWS Secrets Manager, GCP Secret Manager, Vault, Doppler, your platform’s vault) — never from a file the web server can serve.
  4. Fix .gitignore and your build. Add .env* and other secret files to .gitignore, disable source maps in production (or stop deploying the .map), and make sure your deploy step copies built output only — not your whole project folder with .git inside.
  5. Redeploy and re-verify. Push the corrected build, then re-run ExposureCheck (or just request the path yourself) to confirm the file now returns 404/403 and the secret is gone from what’s served.
  6. Scrub git history. A secret that ever sat in a commit lives in history forever. Rewrite it with git filter-repo or BFG Repo-Cleaner, force-push, and have collaborators re-clone. Remember forks and PRs may still carry it.
Order matters. Rotate first. Pulling the file and cleaning history is essential hygiene, but it does nothing for a key that’s already been scraped. Revoking access is what actually closes the door.

Scan your site now