Claude recommends Flask catch-all static routes without securing against sensitive file exposure (.env, .git, .py)
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
- Every time Claude writes a Flask static file catch-all route, it should automatically include the block list above
- Every security audit Claude performs should include testing
/.env,/.git/config, and/<appname>.pyas standard checks - 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.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗