Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset python/PYTHON-FLASK-SEC-017 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects calls to Flask's send_file() and send_from_directory() functions, which serve files directly from the server's file system in HTTP responses. When the filename or path argument to these functions originates from user input (request parameters, URL path segments, form fields), the application is vulnerable to path traversal attacks.
Path traversal (also called directory traversal) occurs when an attacker supplies sequences like ../../../etc/passwd or URL-encoded equivalents (%2e%2e%2f) as the filename. If the application does not sanitize the filename before passing it to send_from_directory() or send_file(), the server will read and return files outside the intended directory -- including application source code, configuration files, private keys, and system files.
send_from_directory() provides partial protection by joining the directory and filename arguments, but it does not prevent traversal if the filename itself contains ../ sequences unless werkzeug.utils.safe_join() or secure_filename() is applied first. send_file() with an absolute path constructed from user input is even more dangerous.
The detection uses Or(calls("send_from_directory"), calls("flask.send_from_directory"), calls("send_file"), calls("flask.send_file")) to flag any use of these functions for manual review. Not every call is vulnerable -- serving a hardcoded filename is safe -- but every call warrants inspection to verify the filename argument cannot be user-controlled.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Arbitrary File Read via Path Traversal
An attacker who can control the filename argument can read any file readable by the web server process. Common targets include /etc/passwd, /etc/shadow (if the server runs as root), application source code, .env files with credentials, SSL private keys, and database files. In Flask applications, the config object and SECRET_KEY are frequently stored in files adjacent to the application.
Source Code and Configuration Disclosure
Flask applications commonly store configuration in app.cfg, .env, or config.py files in the project root. A path traversal in a file-serving route can expose these files directly, leaking database credentials, API keys, and Flask's SECRET_KEY (which enables session forgery).
Private Key and Certificate Theft
Web servers often store TLS private keys, SSH keys, or JWT signing keys on disk. A path traversal vulnerability can expose these keys, enabling an attacker to impersonate the server, decrypt captured traffic, or forge authentication tokens.
Denial of Service via Large File Reads
An attacker can cause the server to read and stream large files (disk images, log files, binary blobs), consuming server memory and network bandwidth and degrading availability for legitimate users.
How to Fix
Recommended remediation steps
- 1Always sanitize filenames from user input with werkzeug.utils.secure_filename() before passing to send_file() or send_from_directory(). secure_filename() strips all directory components and dangerous characters.
- 2Verify that the resolved file path is inside the intended directory by checking os.path.realpath(path).startswith(os.path.realpath(base_dir)) after joining.
- 3Prefer serving user-uploaded files by a server-generated identifier (UUID) stored in a database rather than by the original filename. Map UUID to filename server-side.
- 4Set the as_attachment=True flag when serving user-uploaded files to force the browser to download rather than render them, reducing the risk of stored XSS via uploaded HTML/SVG files.
- 5Use a dedicated file storage service (object storage) or a web server (nginx) for static file serving instead of routing all file downloads through Flask application code.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule uses Or(calls("send_from_directory"), calls("flask.send_from_directory"), calls("send_file"), calls("flask.send_file")) to match both the directly imported function forms and the module-qualified forms. This is a broad audit pattern -- every call to these functions is flagged for manual review, regardless of whether the filename argument is demonstrably user-controlled. The rule surfaces all file-serving locations for inspection. For a dataflow rule that specifically traces user input from Flask request parameters into send_file() or send_from_directory(), a taint-analysis companion rule would complement this audit coverage.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Flask CSV Injection
User input from Flask request parameters flows to csv.writer.writerow() or writerows() without formula character sanitization. Strip or escape leading =, +, -, @ characters to prevent spreadsheet formula injection.
Flask url_for with _external=True
Detects url_for() called with _external=True, which generates absolute URLs using the Host header and can be abused for open redirect or host header injection attacks.
Frequently Asked Questions
Common questions about Flask Insecure Static File Serve
New feature
Get these findings posted directly on your GitHub pull requests
The Flask Insecure Static File Serve rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.