OWASP Web Top 10 — A01

Open Redirect

Open Redirect is a web application vulnerability that allows attackers to redirect users to malicious websites. By manipulating redirect URLs, attackers can use trusted domains to launch phishing campaigns, steal OAuth tokens, and distribute malware while bypassing user suspicion.

What Is Open Redirect?

An Open Redirect vulnerability occurs when a web application accepts user-controllable input to redirect users to other pages without properly validating the destination URL. When an application takes a URL parameter like ?returnUrl= or ?next= and blindly redirects the user to that destination, an attacker can craft a link that appears to point to a trusted domain but ultimately redirects victims to a malicious site.

The danger lies in social engineering amplification. Users are trained to check the domain in their browser's address bar before entering sensitive information. When a phishing link starts with a legitimate domain like https://trusted-bank.com/login?returnUrl=https://evil.com, users see the trusted domain and lower their guard. After clicking, they are seamlessly redirected to the attacker's site, often a pixel-perfect clone of the legitimate service, where credentials or sensitive data are harvested.

Open Redirect vulnerabilities are particularly dangerous in OAuth flows, where the redirect_uri parameter determines where authorization tokens are sent. If an OAuth provider fails to validate redirect URIs against a strict allowlist, attackers can register a malicious application and steal tokens by manipulating the redirect parameter. This has led to critical security breaches in major platforms and continues to be a top attack vector against authentication systems.

How It Works

1
Application accepts a redirect parameter

The application provides a feature that accepts a URL parameter to determine where to redirect the user after an action completes. Common parameters include returnUrl, next, redirect, url, or redirect_uri in OAuth flows.

2
Attacker crafts a malicious URL

The attacker creates a URL that starts with a trusted domain but includes a redirect parameter pointing to their malicious site. For example: https://trusted-site.com/login?returnUrl=https://attacker.com/phishing. The URL appears legitimate because it begins with the trusted domain.

3
Victim clicks the link

The attacker distributes the malicious URL through phishing emails, social media, or compromised websites. The victim sees the trusted domain in the link and clicks it, believing it to be safe. The browser loads the legitimate application's page first, establishing initial trust.

4
Application redirects without validation

The application completes its action (login, logout, OAuth authorization, etc.) and reads the redirect parameter. Without validating that the destination URL is safe, it issues a redirect (HTTP 302/301 or JavaScript window.location) to the attacker-controlled domain.

5
User lands on malicious site

The victim is now on the attacker's website but may not realize it. The transition appears seamless, and the attacker's site may look identical to the legitimate one. The victim enters credentials, payment information, or OAuth tokens are sent to the attacker's redirect URI, completing the compromise.

Vulnerable Code Example

Vulnerable — Java / Spring Boot
@RestController
public class AuthController {

    @PostMapping("/login")
    public ResponseEntity<?> login(
        @RequestBody LoginRequest req,
        @RequestParam(required = false) String returnUrl
    ) {
        // Authenticate user
        User user = authService.authenticate(
            req.getUsername(),
            req.getPassword()
        );

        if (user == null) {
            return ResponseEntity.status(401)
                .body("Invalid credentials");
        }

        // VULNERABLE: No validation on returnUrl
        // Redirects to any URL provided by the user
        if (returnUrl != null) {
            return ResponseEntity.status(302)
                .header("Location", returnUrl)
                .build();
        }

        return ResponseEntity.ok(Map.of("user", user.getUsername()));
    }
}

// An attacker can send a victim to:
// https://trusted-app.com/login?returnUrl=https://evil.com/phishing
//
// After login, the user is redirected to evil.com
// which hosts a clone of the trusted app to steal credentials.

Secure Code Example

Secure — Java / Spring Boot (Allowlist Validation)
@RestController
public class AuthController {

    // SECURE: Define allowlist of trusted domains
    private static final List<String> ALLOWED_DOMAINS = List.of(
        "https://trusted-app.com",
        "https://app.trusted-app.com",
        "https://admin.trusted-app.com"
    );

    @PostMapping("/login")
    public ResponseEntity<?> login(
        @RequestBody LoginRequest req,
        @RequestParam(required = false) String returnUrl
    ) {
        User user = authService.authenticate(
            req.getUsername(),
            req.getPassword()
        );

        if (user == null) {
            return ResponseEntity.status(401)
                .body("Invalid credentials");
        }

        // SECURE: Validate redirect URL against allowlist
        String safeUrl = validateRedirectUrl(returnUrl);

        return ResponseEntity.status(302)
            .header("Location", safeUrl)
            .build();
    }

    private String validateRedirectUrl(String url) {
        // Default safe redirect
        String defaultUrl = "https://trusted-app.com/dashboard";

        if (url == null || url.trim().isEmpty()) {
            return defaultUrl;
        }

        // Check if URL starts with an allowed domain
        boolean isAllowed = ALLOWED_DOMAINS.stream()
            .anyMatch(domain -> url.startsWith(domain));

        // Only allow relative paths or exact domain matches
        if (isAllowed || url.startsWith("/")) {
            return url;
        }

        // Reject external URLs
        return defaultUrl;
    }
}

// Now the application only redirects to pre-approved domains.
// External URLs are rejected and replaced with a safe default.

Types of Open Redirect

Header-Based Redirects

The most common type, where the server sets the Location HTTP header to a user-controlled URL and returns a 301, 302, 303, or 307 status code. The browser automatically follows the redirect. This type is exploited in login flows, logout endpoints, and post-authentication redirects. Attackers craft URLs like /logout?next=https://evil.com to redirect users after logout, often to phishing pages that mimic the login screen.

JavaScript-Based Redirects

The application embeds user-controlled input directly into JavaScript code that performs redirects using window.location, window.location.href, or window.location.replace(). For example, a page might include <script>window.location='[USER_INPUT]'</script>. This is particularly dangerous because it bypasses some server-side redirect protections and can be combined with DOM-based XSS attacks. Modern single-page applications (SPAs) using client-side routing are especially vulnerable.

Meta Refresh Redirects

The application uses an HTML meta tag to perform a delayed redirect: <meta http-equiv="refresh" content="0;url=[USER_INPUT]">. While less common than header or JavaScript redirects, this technique is still found in legacy applications and error pages. The content attribute specifies a delay (usually 0 for immediate redirect) and the destination URL. Because the redirect happens client-side via HTML parsing, it can evade some security filters that only inspect HTTP headers or JavaScript code.

Impact

Open Redirect vulnerabilities may seem less critical than SQL Injection or XSS, but they are powerful enablers of sophisticated attacks. The real-world impact can be severe, especially when combined with social engineering.

Phishing amplification

Attackers leverage the trusted domain to bypass user suspicion and email spam filters. A phishing email containing a link to https://paypal.com/login?next=https://evil.com is far more likely to be clicked than a direct link to an unknown domain. Credential harvesting rates increase dramatically when the attack begins on a legitimate domain.

OAuth token theft

In OAuth 2.0 flows, the redirect_uri parameter determines where authorization codes and tokens are sent. If an OAuth provider doesn't strictly validate redirect URIs, attackers can register a malicious app and manipulate the redirect to steal tokens. This grants full account access without knowing the user's password.

Malware distribution

Attackers use open redirects on trusted domains to bypass browser security warnings and download restrictions. A redirect from a legitimate banking site to a malware download is less likely to trigger security alerts than a direct link from a suspicious domain. This technique is commonly used in drive-by download attacks.

Reputation damage

When a company's domain is used in phishing campaigns or malware distribution, even if it's through an open redirect, it damages brand reputation and user trust. Security researchers and bug bounty programs treat open redirects seriously because they enable real-world attacks and reflect poor security hygiene.

Prevention Checklist

Use an allowlist of trusted domains

Maintain a strict allowlist of permitted redirect destinations. Validate that all redirect URLs start with one of the allowed domains. Reject any external URLs that are not on the allowlist. This is the most effective defense against open redirect attacks and should be applied to all redirect parameters including returnUrl, next, redirect, and OAuth redirect_uri.

Prefer relative paths over full URLs

When possible, only accept relative paths (starting with /) rather than full URLs. This ensures redirects always stay within your domain. For example, accept /dashboard but reject https://evil.com. If you must accept full URLs, parse them and verify the hostname against your allowlist.

Validate using URL parsers, not regex

Use your language's built-in URL parsing library to validate redirect destinations. Regex-based validation is error-prone and can be bypassed with URL encoding, protocol-relative URLs, or malformed URLs. Proper URL parsers (like Java's URI, Python's urllib.parse, or JavaScript's URL API) correctly handle edge cases.

Implement strict OAuth redirect_uri validation

For OAuth providers, require exact-match validation of redirect_uri values. Do not use substring matching or wildcard patterns. Store the exact redirect URI during client registration and compare it byte-for-byte during authorization. Even a single character difference should reject the request.

Use indirect references instead of URLs

Instead of accepting arbitrary URLs, use lookup keys that map to pre-configured destinations. For example, accept ?destination=dashboard and map it server-side to /app/dashboard. This completely eliminates the risk of external redirects while still providing flexible routing.

Add user warnings for external redirects

If you must allow redirects to external domains (for legitimate business reasons), show a clear warning page first. Inform users they are leaving your site and display the destination URL. Require an explicit user action (like clicking a "Continue" button) before completing the redirect. This prevents automated redirects and gives users a chance to detect phishing.

Real-World Examples

2014

Google Open Redirect

Security researchers discovered multiple open redirect vulnerabilities in Google services, including Google Search and Google Maps. Attackers used these to create convincing phishing URLs that started with google.com but redirected to malicious sites. Google has since implemented strict redirect validation, but open redirects remain a common finding in bug bounty programs.

2016

OAuth redirect_uri Exploits

Multiple OAuth providers were found vulnerable to authorization code interception through manipulated redirect_uri parameters. Attackers exploited lax validation to steal tokens and gain full account access. Notable victims included services using Facebook, Google, and Microsoft OAuth. This led to widespread adoption of exact-match redirect URI validation in OAuth 2.0 implementations.

2018

Steam Open Redirect

Valve's Steam platform had an open redirect vulnerability in its web authentication flow. Attackers used steampowered.com redirects to phish Steam credentials and steal game inventories worth thousands of dollars. The vulnerability was widely exploited before being patched, demonstrating how open redirects enable targeted attacks against high-value accounts.

2020

Microsoft Teams Phishing

Attackers discovered open redirect vulnerabilities in Microsoft Teams URLs. They crafted phishing emails with links starting with teams.microsoft.com that redirected to credential harvesting sites. Because the initial URL appeared legitimate, email security filters and users' security awareness training failed to detect the attack, resulting in widespread credential theft.

Ready to Test Your Knowledge?

Put what you have learned into practice. Try identifying and fixing Open Redirect vulnerabilities in our interactive coding challenges, or explore more security guides to deepen your understanding.