Flask SSRF via requests Library

HIGH

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.

Rule Information

Language
Python
Category
Flask
Author
Shivasurya
Shivasurya
Last Updated
2026-03-22
Tags
pythonflaskssrfrequestsurllibserver-side-request-forgerycloud-metadatacross-fileinter-proceduraltaint-analysisCWE-918OWASP-A10
CWE References

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-006 --project .
1
2
3
4
5
6
7
8
9
10
11
rule.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
Cross-file analysis: 2 files

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 flows into outbound HTTP request URLs via the requests library (requests.get, requests.post, requests.put, requests.delete, requests.patch, requests.head, requests.options) or the standard library (urllib.request.urlopen, urllib.request.Request).

SSRF allows attackers to instruct the application server to make HTTP requests to destinations of the attacker's choosing. The server then acts as a proxy, forwarding the response to the attacker. This is particularly severe in cloud environments where the EC2/ECS/GKE metadata endpoint (169.254.169.254) returns instance credentials without authentication when reached from the instance itself.

The rule uses taint analysis to trace the URL argument from Flask request sources through variable assignments and function calls. The .tracks(0) parameter targets the URL positional argument to requests functions, where SSRF occurs. Flows through validate_url() or is_safe_url() are recognized as sanitizers because these functions typically implement allowlist-based URL validation.

Security Implications

Potential attack scenarios if this vulnerability is exploited

1

Cloud Instance Credential Theft

In AWS, GCP, and Azure, the instance metadata service is accessible at http://169.254.169.254/ (or http://169.254.169.254/latest/meta-data/iam/ security-credentials/ on AWS). An attacker who controls the URL parameter causes the Flask server to fetch its own IAM credentials and return them in the response. These credentials give the attacker full API access to the cloud account.

2

Internal Service Discovery and Exploitation

The application server can reach internal services on the private network that are not exposed to the internet: internal APIs, admin dashboards, Kubernetes API servers, Redis instances, and Elasticsearch clusters. SSRF turns an external attacker into an internal network attacker with the server's identity.

3

Port Scanning and Network Topology Mapping

Timing differences in SSRF responses reveal which internal hosts and ports are open. An attacker iterates RFC 1918 addresses and observes connection timeouts vs. refused connections to map the internal network topology, identifying targets for subsequent exploitation.

4

Bypassing IP-Based Access Controls

Many internal services restrict access by source IP address, trusting requests from the application server. SSRF bypasses this control because the request originates from the trusted server. Admin interfaces that are secure against external access become reachable via the vulnerable Flask endpoint.

How to Fix

Recommended remediation steps

  • 1Implement an allowlist of trusted hostnames that the application is permitted to request, and reject any URL whose host is not on the list.
  • 2Resolve the DNS name to an IP address after allowlist validation and verify the resolved IP is not in a private, loopback, or link-local range to prevent DNS rebinding attacks.
  • 3Disable redirects or validate redirect destinations against the allowlist -- requests follows redirects by default and a redirect to 169.254.169.254 bypasses the initial URL check.
  • 4Use a dedicated HTTP client configured to reject private IP ranges at the network level (e.g., SSRF-aware proxy like Smokescreen) rather than relying solely on application-level validation.
  • 5Set short timeouts and response size limits on outbound requests to limit damage from requests to slow 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() -- all of which can deliver attacker- controlled URL strings. Sinks: requests.get(), requests.post(), requests.put(), requests.delete(), requests.patch(), requests.head(), requests.options() -- and stdlib equivalents urllib.request.urlopen() and urllib.request.Request(). The .tracks(0) parameter targets the URL argument at position 0, the destination that determines where the server sends the request. Sanitizers: validate_url() and is_safe_url() are recognized as sanitizing functions. These typically implement allowlist checks against a set of trusted hostnames. A flow through either function before reaching a requests sink is treated as sanitized. The rule follows URL values through variable assignments and cross-file function calls, catching SSRF patterns where the URL is assembled in a utility function separate from the Flask route handler.

Compliance & Standards

Industry frameworks and regulations that require detection of this vulnerability

OWASP Top 10
A10:2021 - Server-Side Request Forgery (SSRF) -- standalone category since 2021
CWE Top 25
CWE-918 -- Server-Side Request Forgery in dangerous weaknesses list
PCI DSS v4.0
Requirement 6.2.4 -- protect against SSRF and injection attacks
NIST SP 800-53
SC-7: Boundary Protection; SI-10: Information Input Validation
Cloud Security Alliance
CCM IVS-09 -- network segmentation controls for cloud workloads

References

External resources and documentation

Similar Rules

Explore related security rules for Python

Frequently Asked Questions

Common questions about Flask SSRF via requests Library

SSRF was promoted to its own category in OWASP Top 10 2021 (A10) because of its outsized impact in cloud-native architectures. Traditional injection attacks target the application itself. SSRF weaponizes the application's network position -- the server can reach internal services, cloud metadata endpoints, and private networks that the attacker cannot touch directly. The cloud metadata attack alone justifies a CRITICAL finding in AWS/GCP/Azure deployments.
Disabling redirects (allow_redirects=False) prevents the attacker from redirecting through 169.254.169.254 after an initial allowed URL. But it does not prevent SSRF when the initial URL itself is attacker-controlled. Both controls are needed: allowlist validation of the initial URL AND redirect validation if redirects are enabled.
An attacker controls a domain on the allowlist (or tricks you into allowlisting it) and sets its DNS TTL to 0. The validation resolves it to a legitimate IP. By the time requests.get() resolves it for the actual connection, the attacker has changed the DNS record to 169.254.169.254. The fix is to resolve DNS once, validate the resolved IP, and use the IP for the actual connection.
Yes. The sink list includes urllib.request.urlopen() and urllib.request.Request() in addition to all requests library methods. Both libraries are tracked because real codebases mix them, especially when requests is not available or when interacting with Python standard library code.
Scheme validation is necessary but not sufficient. http://169.254.169.254/ is a valid http:// URL. After validating the scheme, you must also validate the resolved hostname against an allowlist and check that the resolved IP is not in a private or reserved range.
SEC-006 focuses on SSRF via the requests and urllib libraries -- the most common Python HTTP clients. SEC-011 focuses on tainted URL host components specifically, covering cases where the attacker controls only the hostname portion of a URL that is otherwise application-constructed. Running both rules provides broader coverage across different code patterns.
Use a local HTTP server on 127.0.0.1:8080 and supply http://127.0.0.1:8080/ as the URL parameter. A successful response from your own server confirms the SSRF is real. For cloud metadata testing, use a mock endpoint that returns a fake credential response instead of the actual metadata service.

New feature

Get these findings posted directly on your GitHub pull requests

The Flask SSRF via requests Library rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.

See how it works