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-AUDIT-005 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects calls to Flask's url_for() with the _external=True keyword argument. When _external=True is set, url_for() generates an absolute URL (including scheme and host) rather than a relative path. Flask constructs the host portion of this URL from the incoming HTTP request's Host header. If the Host header is not validated, an attacker can supply an arbitrary host value and cause url_for() to return a URL pointing to an attacker-controlled domain.
This becomes a direct security vulnerability when the generated URL is used in an HTTP redirect (redirect(url_for(..., _external=True))), a password-reset email link, an OAuth redirect_uri, or any other context where the URL is sent to a user and the user's browser will follow it. In these cases, host header injection escalates to an open redirect or phishing attack.
The detection uses calls("url_for", match_name={"_external": True}) -- an Or-free pattern that matches any call to url_for() where the _external keyword argument is present and set to True. This is an audit-grade rule: not every url_for(_external=True) is vulnerable, but every use warrants review to confirm that the generated URL is not used in a redirect or emailed to a user without host validation.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Open Redirect via Host Header Injection
If the generated URL is passed to redirect(), an attacker can set the Host header to an attacker-controlled domain. The application will return a 302 response pointing the user's browser to the attacker's site. Phishing, credential harvesting, and malware delivery are the typical payloads.
Password Reset Link Hijacking
Password reset flows frequently generate absolute URLs with _external=True for email links. If an attacker can influence the Host header during the reset request (possible in some proxy and load-balancer configurations), the reset link in the email will point to the attacker's domain, handing them the reset token.
OAuth redirect_uri Manipulation
OAuth flows that use url_for(_external=True) to build the redirect_uri parameter can be manipulated to point to attacker-controlled endpoints, capturing authorization codes and access tokens.
Cache Poisoning via Host Header
If the externally-generated URL is cached (CDN, application cache) with the attacker's host value, subsequent users who receive the cached response will see URLs pointing to the attacker's domain.
How to Fix
Recommended remediation steps
- 1Set app.config['SERVER_NAME'] to your production domain so Flask uses a fixed host for external URL generation rather than trusting the Host header.
- 2If you must generate external URLs without SERVER_NAME, validate that the generated URL's host matches an explicit allow-list of known-good domains before using it in redirects or emails.
- 3Prefer relative URLs (url_for() without _external=True) for internal redirects within the application.
- 4For email links, construct absolute URLs from a hardcoded BASE_URL configuration value rather than from request context.
- 5Add server-side Host header validation middleware if your deployment architecture sends the original Host header through proxies.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule uses calls("url_for", match_name={"_external": True}) to match any call to the url_for() function where the _external keyword argument is present and set to True. This is a broad audit pattern -- it flags all such calls for manual review, not only those that directly feed into redirect() or email sending. The rule does not perform dataflow analysis from the generated URL to its use site. Use this finding as a signal to review each flagged call and determine whether the generated URL reaches a redirect or email context without host validation.
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 Code Injection via exec()
User input from Flask request parameters flows to exec() or compile(). exec() cannot be safely sanitized -- redesign the feature to avoid dynamic code execution.
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 render_template_string Usage
Detects any use of render_template_string(), which renders Jinja2 templates from Python strings and is inherently adjacent to Server-Side Template Injection (SSTI) vulnerabilities.
Frequently Asked Questions
Common questions about Flask url_for with _external=True
New feature
Get these findings posted directly on your GitHub pull requests
The Flask url_for with _external=True rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.