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-012 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects open redirect vulnerabilities in Flask applications where user-controlled input from HTTP request parameters flows to Flask's redirect() function without URL validation. An open redirect occurs when the application accepts a URL or path from user input and issues an HTTP redirect (302 or 301) to that destination without verifying it belongs to a trusted origin.
Open redirects are endemic in Flask login flows: after authentication, the application redirects to the "next" URL parameter. Without validation, an attacker sends victims to a URL like: https://legitimate-app.com/login?next=https://evil.com/phishing
The victim sees the legitimate application's login page, authenticates, and is transparently redirected to the attacker's site -- all appearing as a natural post-login navigation. This is a primary vector for credential phishing because the legitimate domain is visible in the initial URL shared with the victim.
The taint analysis traces the URL value from Flask request sources through variable assignments and function calls to the Flask redirect() function at argument position 0. Flows through url_for() or url_has_allowed_host_and_scheme() are recognized as sanitizers: url_for() generates only application-internal URLs, and url_has_allowed_host_and_scheme() (from Werkzeug) validates that a URL's host and scheme are acceptable.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Phishing Attack Amplification via Trusted Domain
Attackers craft URLs like https://yourapp.com/login?next=https://phishing.com/steal and distribute them. Victims who click the link land on the real application login page, authenticate normally, and are redirected to the phishing site. Because the initial URL shows the legitimate domain, anti-phishing training does not help. The application's credibility is weaponized against its own users.
OAuth Token Theft via Redirect URI Manipulation
In OAuth flows, a vulnerable redirect_uri parameter in the authorization request can redirect access tokens to an attacker-controlled site. If the Flask application uses the "next" parameter in OAuth callbacks without validation, the access token or authorization code in the redirect URL is sent to the attacker's server.
SSRF Gadget in Redirect Chains
Internal services that trust redirects from the application server may follow a redirect to an internal endpoint. In microservice architectures, an open redirect in a Flask service can be chained with redirect-following HTTP clients in other services to reach internal APIs that the attacker cannot access directly.
Session Fixation via External Redirect with Cookie Setting
An attacker who controls the redirect destination can combine the open redirect with a response that sets a cookie or manipulates browser storage, then redirects back to the application with a known session token (session fixation). The redirect through a legitimate domain gives the attacker's cookies the opportunity to be stored.
How to Fix
Recommended remediation steps
- 1For post-login and post-action redirects, use url_for() with a route name rather than accepting a redirect URL from the request -- url_for() can only generate URLs for routes defined in the application.
- 2If you must accept a redirect URL from user input, validate it with werkzeug's url_has_allowed_host_and_scheme() which checks that the URL's host matches the application's configured allowed hosts.
- 3Maintain an explicit allowlist of external domains that the application is permitted to redirect to, and reject any redirect URL whose host is not on the list.
- 4Implement a redirect disclaimer page for redirects to external sites -- show users where they are going and require confirmation before navigating away from the application.
- 5Log all redirects to external domains for anomaly detection -- legitimate use rarely generates high volumes of redirects to diverse external domains.
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 URL strings. The "next" parameter in login flows is the most common source. Sinks: Flask's redirect() function. The .tracks(0) parameter targets the URL argument at position 0 -- the redirect destination. The HTTP status code argument at position 1 is not tracked. Sanitizers: url_for() and url_has_allowed_host_and_scheme() are recognized as sanitizing transformations. url_for() generates only application-internal URLs (it cannot produce external URLs). url_has_allowed_host_and_scheme() from Werkzeug validates that the host and scheme are in the application's allowed set. A redirect URL that passes through either is treated as safe. The rule follows URL values through variable assignments, string manipulation, and cross-file function calls to the redirect() sink.
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.
Flask SSRF via Tainted URL Host
User input from Flask request parameters is used to construct the host component of an outbound HTTP request URL. Validate the host against an explicit allowlist before making server-side requests.
Frequently Asked Questions
Common questions about Flask Open Redirect
New feature
Get these findings posted directly on your GitHub pull requests
The Flask Open Redirect rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.