Claude recommends Flask catch-all static routes without securing against sensitive file exposure (.env, .git, .py)

Resolved 💬 2 comments Opened Jun 5, 2026 by Meelex Closed Jul 12, 2026

Summary

When helping users build Flask web applications, Claude routinely recommends or accepts a catch-all static file route pattern that exposes sensitive files in the working directory to the public web — including .env (API keys, database credentials, secrets), .git/config (full git history and repository details), *.py source files, and *.db databases.

The vulnerable pattern Claude recommends

STATIC_DIR = os.path.dirname(os.path.abspath(__file__))

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def serve(path):
    try:
        if path:
            return send_from_directory(STATIC_DIR, path)
    except NotFound:
        pass
    return send_from_directory(STATIC_DIR, 'index.html')

If the Flask app lives in the same directory as .env, anyone can request https://yourapp.com/.env and receive the full contents — Stripe keys, database passwords, JWT secrets, admin credentials.

Real-world impact

This was discovered in a production app built with Claude's assistance. The .env file was publicly accessible for an extended period, exposing live Stripe API keys, webhook secrets, a JWT signing key, admin credentials, and all application secrets. The .git directory was also fully accessible.

The fix Claude should always include

BLOCKED_EXTENSIONS = {'.py', '.db', '.sqlite', '.env', '.cfg', '.ini', '.log', '.key', '.pem'}

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def serve(path):
    parts = path.split('/')
    filename = parts[-1] if parts else ''
    # Block dotfiles, dotdirectories, source files, and databases
    if (any(p.startswith('.') for p in parts)
            or any(filename.endswith(ext) for ext in BLOCKED_EXTENSIONS)):
        abort(404)
    try:
        if path:
            return send_from_directory(STATIC_DIR, path)
    except NotFound:
        pass
    return send_from_directory(STATIC_DIR, 'index.html')

Requested behavior change

  1. Every time Claude writes a Flask static file catch-all route, it should automatically include the block list above
  2. Every security audit Claude performs should include testing /.env, /.git/config, and /<appname>.py as standard checks
  3. Claude should proactively warn when it sees an existing catch-all route without file filtering

This is OWASP A05:2021 Security Misconfiguration and affects any Flask SPA pattern where the app and static files share a working directory — which is extremely common in small projects and exactly the kind of project Claude helps build most often.

Reported by Meelex who was notified of the vulnerability in their production app by a third-party security researcher who discovered and responsibly disclosed it.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗