CWE-601: URL Redirection to Untrusted Site (Open Redirect)
Overview
Open redirect vulnerabilities occur when an application accepts user-controllable input and uses it to redirect users to other websites without proper validation. Attackers exploit this by crafting malicious links that appear to come from trusted domains but redirect victims to attacker-controlled sites.
Example: User clicks https://trusted-site.com/login?redirect=http://evil-site.com and the application redirects to the attacker-controlled evil-site.com.
OWASP Classification
A01:2025 - Broken Access Control
Risk
Open redirect vulnerabilities enable various attacks:
- Phishing attacks: Users trust the initial domain, click the link, and end up on a fake login page
- Credential theft: Fake pages that mimic the trusted site to steal credentials
- Malware distribution: Redirect to drive-by-download sites distributing malware
- OAuth token theft: Intercept authorization codes or access tokens in OAuth flows
- XSS bypass: Chain with XSS via javascript: or data: URL schemes
- Business reputation damage: Trusted domain used to distribute spam or malicious content
- SEO poisoning: Manipulate search rankings by abusing trusted domains
The impact is magnified because users see and trust the original domain in the link, lowering their guard.
Common Attack Vectors and Vulnerable Patterns
Attackers leverage open redirects to:
- Bypass URL filters and spam blockers
- Conduct phishing attacks that appear to originate from trusted domains
- Steal credentials via fake login pages
- Distribute malware from seemingly trusted sources
- Bypass content security policies in some contexts
Open redirects are commonly found in:
- Post-login redirect parameters (
?next=,?returnUrl=,?redirect=) - Logout handlers that redirect to confirmation pages
- OAuth/SAML flows with redirect parameters
- Payment or checkout flows with "continue" URLs
Remediation Steps
Core principle: Never allow untrusted input to control navigation or redirect targets; all redirect destinations must be server-defined or selected from a strict allowlist.
Locate the open redirect vulnerability
- Review the security findings to identify the specific file, line number, and redirect operation
- Identify all parameters that control redirect destinations (
?next=,?redirect=,?returnUrl=,?continue=) - Trace how untrusted data (user input, external files, databases, network requests) flows to the redirect
- Locate the code that performs redirects (
Response.Redirect(),redirect(),header("Location:"),sendRedirect()) - Check if the redirect destination is validated before use
- Map all redirect endpoints and their input sources
Use allowlist of permitted redirect destinations (Primary Defense)
- Define explicit allowlist: Specify permitted redirect URLs or paths in configuration
- For internal redirects, allowlist relative paths only:
/dashboard,/profile,/settings - For external redirects, allowlist specific full URLs:
https://trusted-partner.com/callback - Store allowlist in configuration files: Never in untrusted data
- Validate redirect parameter against allowlist: Check BEFORE redirecting
- Use exact string matching or strict prefix matching: Not substring or regex that can be bypassed
- Reject any redirect not in allowlist: Show error or use default redirect
- Normalize URLs before comparison: Handle
//,%2fencoding to prevent bypass - Why this works:
- Allowlist enforcement prevents unauthorized redirects: Only pre-approved destinations can be accessed
- Attackers cannot manipulate destination: Input validation rejects any URL not explicitly permitted
Eliminate direct use of untrusted data in redirects
- Replace URL parameters with opaque identifiers: Use numeric IDs, tokens instead of URLs
- Map identifiers to actual redirect URLs server-side:
1 → /dashboard,2 → /profile - Accept only the identifier in redirect parameter:
?next=2 - Look up actual URL from server-side mapping: User cannot specify arbitrary URLs
- Redirect to the mapped URL: This prevents arbitrary destination specification
- Benefits: Simple to validate (must be valid ID), easy to maintain and audit
Add strict URL validation if direct URLs are required (Defense in Depth)
- Parse redirect URLs using proper URL parsing library: Not regex
- Validate scheme is
http://orhttps://only: Blockjavascript:,data:,file: - Verify domain exactly matches allowed domain: Prevent subdomain attacks
- Reject URLs containing
@symbols: Bypass techniqueuser@attacker.com:password@trusted.com - Normalize URLs before validation: Resolve
../,//,%00, URL encoding - Ensure exact domain matching: Not substring (
evil.trusted.comortrusted.com.evil.com) - Perform validation server-side only: Never trust client-side validation
Use redirect confirmation for external destinations
- For any redirect to external domains: Show an interstitial warning page
- Display full destination URL to user: Not shortened or encoded
- Require explicit user action to continue: Button click, not automatic redirect
- Add
rel="noopener noreferrer"to external links: Prevent window.opener exploitation - Log all external redirects: Security monitoring and abuse detection
- Consider CAPTCHA for high-risk external redirects: Prevent automated abuse
Test and verify open redirect protection thoroughly
- Test that only allowlisted destinations work
- Test bypass attempts:
//evil.com,/\\evil.com,https://evil.com@trusted.com - Test subdomain bypass:
https://trusted.com.evil.com - Test protocol-relative URLs:
//attacker.com - Test dangerous schemes:
javascript:alert(1),data:text/html,<script>alert(1)</script> - Test URL encoding bypasses:
%68%74%74%70%3a%2f%2fevil.com - Test double encoding:
%2568%2574%2574%2570 - Test path traversal in redirects:
https://trusted.com/../attacker.com - Verify legitimate redirects to allowed destinations still work
- Re-scan with the security scanner to confirm the issue is resolved
- Check for any new findings introduced by the changes
Language-Specific Guidance
- Python - Flask, Django, FastAPI - urlparse validation and allowlisting
- Java - Servlets, Spring MVC, Jakarta EE - URI validation and redirect protection
- JavaScript/Node.js - Express, Koa - URL parser validation and same-origin checks
- C# - ASP.NET Core, MVC - Url.IsLocalUrl() and allowlist validation
- PHP - Laravel, Symfony - parse_url validation and header redirects
Dynamic Scan Guidance
For guidance on remediating this CWE when detected by dynamic (DAST) scanners:
- Dynamic Scan Guidance - Analyzing DAST findings and mapping to source code