Back to scan results
Check 9 of 24

Sensitive Files Exposed

We send HTTP GETs to a list of well-known filenames that should never be served publicly: configuration files holding database passwords, version control metadata, debug pages, and forgotten backup archives.

What this check probes

Each request is a single GET; we look for HTTP 200 with a non-empty body or recognizable file signatures. The probe list:

  • App config — /.env, /.env.local, /config.php, /wp-config.php, /wp-config.php.bak, /web.config, /application.yml, /appsettings.json.
  • Version control — /.git/config, /.git/HEAD, /.svn/entries, /.hg/store. Even the config alone lets an attacker reconstruct the full source tree.
  • Editor / OS junk — /.DS_Store (Mac), /Thumbs.db, /.idea/workspace.xml (JetBrains).
  • Debug pages — /phpinfo.php, /info.php, /test.php, /debug.
  • Backups — /backup.sql, /database.sql, /dump.sql, /backup.zip, /site.tar.gz, /{domain}.zip.
  • Discovery hints — /robots.txt, /sitemap.xml, /.well-known/security.txt. Robots.txt is informational only — no failure if found.

Why this matters for PCI DSS

A leaked .env file usually contains: database password, payment gateway API keys, session encryption secret, mail credentials, and OAuth client secrets. Any one of those is a complete compromise.

An exposed /.git directory lets an attacker run git-dumper and reconstruct your entire source repository — including any committed-then-removed credentials in history.

PCI DSS 4.0 Requirement 6.4.3 covers payment-page integrity. Requirement 8.3.1 requires strong authentication factors. Requirement 3.5.1 requires that cryptographic keys be protected. Leaking config files breaks all three at once.

How to fix it

1. Move secrets out of the document root. Best practice: read secrets from environment variables (set by your process supervisor — systemd, supervisord, IIS app pool identity), not files inside the web root.

2. Block hidden files at the web server.

nginx:

location ~ /\.(?!well-known) {
    deny all;
    return 404;
}
location ~ \.(sql|bak|zip|tar|gz|env)$ {
    deny all;
    return 404;
}

Apache:

<FilesMatch "^\.">
    Require all denied
</FilesMatch>
<FilesMatch "\.(sql|bak|zip|env)$">
    Require all denied
</FilesMatch>

IIS — add to web.config:

<system.webServer>
  <security>
    <requestFiltering>
      <hiddenSegments><add segment=".git" /><add segment=".env" /></hiddenSegments>
      <fileExtensions><add fileExtension=".sql" allowed="false" /><add fileExtension=".bak" allowed="false" /></fileExtensions>
    </requestFiltering>
  </security>
</system.webServer>

3. Rotate any credentials that were in a leaked file. Assume the file was downloaded the moment it became reachable.

4. Delete the debug pages. phpinfo.php has no place on a production server.

5. Add to your CI: a deploy script that refuses to publish if it finds .env, .git, or .sql files in the upload payload.

Fixed it? Re-run the scan to confirm.

Run scan again