Security audit guide

How to check if a website has exposed files

Sensitive files — environment configs, git repositories, source maps, database backups — end up publicly accessible more often than most developers expect. This guide shows you exactly how to audit your own site for the most common exposures before someone else finds them.

Only test sites you own. These techniques are standard defensive security practice for your own infrastructure. Probing a site you don't own or haven't been authorized to test is unauthorized access under the CFAA (US), Computer Misuse Act (UK), and equivalent laws globally — regardless of intent.

What commonly gets exposed and why it matters

The same deployment mistakes happen across every hosting platform and every stack. These are the paths worth checking first, in rough order of impact:

  • /.env Critical

    The project's environment variable file — contains API keys, database passwords, third-party service credentials, and signing secrets. Bots probe this path within minutes of a site going live. Variants to check: /.env.local, /.env.production, /.env.backup, /.env.old.

  • /.git/config Critical

    If the .git directory is publicly accessible, an attacker can reconstruct the entire repository using tools like GitTools — even if the repo is private. The config file reveals the remote URL (which may include an embedded access token for HTTPS clones), branch names, and author configuration. The rest of the history is typically downloadable from /.git/objects/.

  • /*.js.map High

    JavaScript source maps reconstruct your original, unminified source code from a compiled bundle. A source map for a React or Vue app exposes your full component tree, TypeScript types, comments, file structure, and any hardcoded values that were present in development — including keys and credentials that someone added "temporarily" to a config file.

  • /config.json  /config.yml High

    Application config files placed in the webroot. Some frameworks and CMSes create these in predictable locations — /config/database.yml for Rails, /config.json for various Node apps. If the file contains credentials (even development ones), they're now public.

  • /backup.sql  /dump.sql Critical

    Database backups placed in the webroot during maintenance and never removed. These contain a full copy of your data, often including user PII, hashed passwords, and payment records. Common naming patterns: backup.sql, dump.sql, db.sql, database.sql.gz, yoursite.sql.

  • /wp-config.php  /phpinfo.php High

    WordPress configuration (database credentials, secret keys, salts) and PHP environment info dumps. These are probed constantly on any domain. phpinfo.php is less exploitable but reveals your server stack, PHP version, loaded extensions, and environment variables — useful for attackers planning a more targeted attack.

Manual checks with curl

The quickest way to probe a specific path is a single curl command that reports only the HTTP status code without fetching the full body:

curl -s -o /dev/null -w "%{http_code}" https://your-site.com/.env

Run this for each path you want to check. The meaning of each response code:

HTTP status What it means Safe?
200 The path exists and is being served — may contain file contents No — investigate immediately
301 / 302 Redirect — follow the redirect and check what it leads to Check destination
403 Access denied — the path exists but the server is blocking access Yes, if consistently applied
404 Path not found — the file isn't there or the server isn't revealing it Yes
Check that 200 actually returns content. Some servers return a 200 with an empty body or an HTML error page for all requests (a "soft 404"). If you get a 200, run the curl without -o /dev/null to see what the response body actually contains: curl -s https://your-site.com/.env | head -20

A complete shell audit loop

This one-liner probes the most common high-risk paths and reports each HTTP status in a single pass:

SITE="https://your-site.com"
for path in /.env /.env.local /.env.production /.env.backup \
            /.git/config /.git/HEAD \
            /config.json /config.yml /config.php \
            /wp-config.php /phpinfo.php \
            /backup.sql /dump.sql /db.sql /database.sql; do
  code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$SITE$path")
  echo "$code  $SITE$path"
done

Any line showing 200 warrants a closer look. Pipe through grep "^200" to filter for hits only.

Checking for a publicly accessible .git directory

If /.git/config returns 200, confirm the extent of the exposure. A browseable .git/ directory lets an attacker download the entire object store:

# Check if the directory listing is browseable
curl -s https://your-site.com/.git/ | grep -i "Index of"

# Check if packed refs are accessible (reveals all branch/tag SHAs)
curl -s -o /dev/null -w "%{http_code}" https://your-site.com/.git/packed-refs

# Fetch the HEAD file to confirm the active branch
curl -s https://your-site.com/.git/HEAD

A HEAD response of ref: refs/heads/main confirms the repo is accessible. At this point, refer to the fix guide — the server config blocks in Step 3 cover how to deny /.git/ access on Nginx, Apache, Vercel, and Netlify.

Finding source maps and bundled secrets in browser DevTools

Not all exposures are path-accessible files. JavaScript bundles built with source maps enabled — the default in most Vite, webpack, and Create React App configurations — leak your original source code via the browser's DevTools debugger.

Check for source maps in DevTools

  1. Open the site in Chrome or Firefox and open DevTools (F12).
  2. Go to the Sources tab (Chrome) or Debugger tab (Firefox).
  3. Look for a tree under "webpack://", "vite://", or similar. If you see your original file names (e.g. src/components/App.tsx), source maps are enabled and your original code is exposed to anyone who opens DevTools.
  4. If you find source maps: set productionSourceMap: false (Vite), devtool: false (webpack), or GENERATE_SOURCEMAP=false (Create React App) in your build configuration, then redeploy.

Check the Network tab for .map files

  1. Open DevTools → Network tab. Check "Preserve log."
  2. Reload the page.
  3. Filter by ".map" in the request search box.
  4. Any *.js.map or *.css.map request with a 200 response means source maps are being served publicly. Click the request to verify the response contains your original source.

Scan the JavaScript bundle for hardcoded secrets

Even without source maps, compiled JavaScript bundles frequently contain hardcoded API keys or credentials that were embedded at build time. These are invisible to DevTools navigation but readable in the raw bundle text:

# Download the main bundle and grep for common key patterns
curl -s "$(curl -s https://your-site.com/ | grep -oE 'src="[^"]+\.js"' | head -1 | grep -oE '"[^"]+"' | tr -d '"')" \
  | grep -oE '(sk_live|sk_test|AKIA|ghp_|AIza|pk_live)[A-Za-z0-9_\-]{10,}'

This is exactly what ExposureCheck automates — it fetches your live bundle and matches it against 40+ provider-specific key patterns, flagged by severity.

Automated scanning with ExposureCheck

The manual checks above are effective but time-consuming for a thorough audit. ExposureCheck runs the same probes automatically in your browser — no installation, no signup, no data stored server-side:

Run ExposureCheck on your site →

ExposureCheck covers:

  • Path probing/.env and common variants, /.git/config, and other high-risk paths
  • Bundle scanning — fetches your served JavaScript and matches 40+ API key and credential patterns (AWS, OpenAI, Stripe, GitHub, Supabase, Twilio, Google Cloud, and more)
  • Severity grading — each finding is rated Critical / High / Medium / Low with a plain-English explanation
  • Source map detection — flags publicly accessible .js.map files

For paths not covered by ExposureCheck (database backup files, custom config paths, legacy admin panels), supplement with the manual loop above.

Interpreting what you find

Not every 200 response is equally urgent. Use this to triage:

  • Exposed .env or credential file: Treat as an active incident. Rotate credentials immediately — before removing the file, before anything else. Follow the full remediation guide.
  • Accessible .git/config: Block the path immediately at your server level and assess whether the repository has already been reconstructed. If the repo is private and contains secrets in its history, rotate any credentials that appeared in any commit.
  • Source maps enabled: Not an incident requiring immediate credential rotation, but a code-confidentiality issue. Rebuild with source maps disabled and redeploy. Priority depends on how sensitive your source code is.
  • Hardcoded key in a bundle: Rotate the exposed credential and move the value to a proper environment variable injected at build or runtime.
  • Accessible database backup: Treat as a critical data breach. The file must be removed immediately, the platform security team notified, and affected users informed per your GDPR/CCPA obligations.

When to run an exposure audit

Build this into your deployment process rather than treating it as a one-time check:

  • Before every public launch. The window between "deployed" and "discovered by a scanner" is measured in minutes for common paths like /.env.
  • After changing hosting platforms. Moving from Vercel to Netlify, or from a managed platform to a VPS, changes what gets served and what gets blocked — a deny rule that worked on the old platform may not carry over.
  • After modifying your deploy pipeline. If you changed how your CI/CD step publishes files — a new build script, a new artifacts directory, a new deploy action — verify the new config doesn't inadvertently include files it shouldn't.
  • After adding a new third-party service. New services typically mean new credentials in your environment. It's worth confirming they haven't been accidentally included in a build artifact.
  • Quarterly, as a baseline. Configurations drift, new files get added, and what was safe last quarter might not be safe today.

Frequently asked questions

What is the fastest way to check if a site has an exposed .env file?

Open a terminal and run:

curl -s -o /dev/null -w "%{http_code}" https://your-site.com/.env

A 200 response means the file is publicly accessible. Anything other than 200 is safe — 404 means the path doesn't exist, 403 means access is denied. You can also navigate to the URL directly in an incognito browser window and see the file contents if it's exposed.

How do I know if a site's .git folder is publicly exposed?

Probe https://your-site.com/.git/config — if you get a 200 response with INI-formatted text starting with [core], the folder is publicly accessible. This exposes the remote URL, branch names, and potentially credentials stored in the config. Run:

curl -s https://your-site.com/.git/config | head -5
What does an exposed source map actually reveal?

A JavaScript source map (.js.map file) reconstructs your original, unminified source code from a compiled bundle. If your app was built from TypeScript or a framework like React or Vue, the source map can expose your full component tree, TypeScript types, comments, file structure, and any hardcoded values that were present during development — including API keys someone added "temporarily" to a config file.

Can I check a site I don't own for exposed files?

Only audit sites you own or have explicit written permission to test. Probing a third-party site without authorization may violate the Computer Fraud and Abuse Act (US), the Computer Misuse Act (UK), and equivalent laws in other jurisdictions — even if your intent is responsible disclosure. If you discover an exposure on a site you don't own and want to report it, contact the site owner or their security team directly without downloading any data.

How often should I audit my own site?

Run a check before every public launch, after any major infrastructure change (new hosting platform, new deploy pipeline), and after adding new services that introduce secrets. A quarterly check is a reasonable baseline for live production sites.

Does ExposureCheck cover all the paths I should check?

ExposureCheck probes the most commonly exposed paths — .env variants, .git/config, source maps — and scans your served JavaScript bundles for hardcoded API keys matching 40+ provider patterns. For a deeper manual audit (custom config file paths, backup files, legacy admin panels specific to your stack), supplement with the manual curl loop in this guide.

Found something? Follow the step-by-step remediation guide →

Also in the Copper Bay Labs ship-safety suite

Exposed files are one part of a broader pre-launch security and compliance picture: