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-011 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects Server-Side Request Forgery (SSRF) in Flask applications where user-controlled input from HTTP request parameters is used as the host component of a URL that is then passed to outbound HTTP request functions (requests.get, requests.post, requests.put, requests.delete, and stdlib urllib equivalents).
This is distinct from PYTHON-FLASK-SEC-006, which covers cases where the entire URL is user-supplied. This rule covers a subtler pattern: the application constructs a URL with an attacker-controlled hostname, for example: host = request.args.get('service') url = f'https://{host}/api/data' response = requests.get(url)
The developer may believe this pattern is safe because the scheme and path are hardcoded. However, the attacker controls where the request is sent. By supplying 169.254.169.254 as the host, they redirect the request to the cloud metadata endpoint. By supplying an internal service hostname, they pivot to unexposed internal APIs.
The taint analysis traces the host value from Flask request sources through string interpolation and f-string construction to the URL argument of requests functions at position 0. Flows through validate_host() or is_safe_url() are recognized as sanitizers because these functions typically implement hostname allowlist checks.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Cloud Metadata Service Credential Theft
An attacker supplies 169.254.169.254 (AWS/GCP/Azure metadata endpoint) as the host parameter. The Flask server makes a request to its own metadata service, receives IAM credentials (AWS: /latest/meta-data/iam/security-credentials/), and the application may return this response to the attacker. This is one of the highest-impact SSRF attacks in cloud-hosted applications.
Internal Service Discovery
The attacker iterates internal hostnames and IP addresses. Services that are not exposed to the internet -- databases, admin panels, internal APIs, container orchestration endpoints -- respond to requests from the Flask container because they trust traffic from within the internal network. The attacker maps the internal topology through timing and response differences.
Authentication Bypass on Internal Services
Internal services often trust requests from the application server by source IP. An attacker who controls the host parameter can make the Flask server request any internal endpoint with the server's trusted identity, bypassing network-level access controls that would otherwise block external access.
Server-Side Port Scanning via Error Differentiation
Different error responses for connection refused, connection timeout, and successful connection reveal which ports are open on internal hosts. An attacker who can control the host (and optionally port) component of the URL can build a comprehensive port map of the internal network through the Flask endpoint.
How to Fix
Recommended remediation steps
- 1Maintain an explicit allowlist of service hostnames that the application is permitted to call and reject any host not on the list before constructing the URL.
- 2Consider removing the host parameter entirely if the set of callable services is small and known at deployment time -- hardcode the URLs in configuration rather than accepting them from HTTP requests.
- 3After allowlist validation, resolve the hostname to an IP address and verify it is not in a private, loopback, or link-local range to prevent DNS rebinding attacks that bypass hostname allowlists.
- 4Use a service registry or service discovery mechanism (Consul, Kubernetes service names) that constrains reachable services at the infrastructure level rather than relying on application validation alone.
- 5Set a short timeout and response size limit on all server-side HTTP requests to limit the impact of SSRF to slow or large internal services.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
Scope: global (cross-file taint tracking across the entire project). Sources: Flask HTTP input methods -- request.args.get(), request.form.get(), request.values.get(), request.get_json() -- which can deliver attacker-controlled hostname strings. Sinks: requests.get(), requests.post(), requests.put(), requests.delete() -- and urllib.request.urlopen() and urllib.request.Request(). The .tracks(0) parameter targets the URL argument at position 0. This rule specifically catches patterns where user input is interpolated into a URL string (f-string, .format(), concatenation) before reaching the HTTP client function. Sanitizers: validate_host() and is_safe_url() are recognized as sanitizing functions. These are expected to implement allowlist validation against a set of trusted hostnames. A host value that passes through either function before being used in URL construction is treated as sanitized. The rule follows host values through f-string construction, string concatenation, and cross-file function calls where the URL is assembled in a utility module before being passed to the HTTP client.
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 SSRF via requests Library
User input from Flask request parameters flows to outbound HTTP request URLs via the requests library. Validate and allowlist target hosts before making server-side requests.
Django Tainted SQL String Construction
User input is used to construct a SQL string that flows to a database execution function, enabling SQL injection via string building.
Lambda Command Injection via asyncio.create_subprocess_exec()
Lambda event data flows to asyncio.create_subprocess_exec(), enabling argument injection in async Lambda handlers.
Frequently Asked Questions
Common questions about Flask SSRF via Tainted URL Host
New feature
Get these findings posted directly on your GitHub pull requests
The Flask SSRF via Tainted URL Host rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.