# Open redirect via weak origin check

Redirect targets validated by substring, glob, or hostname-only checks instead of full origin parse

_Area: Web infrastructure and server-side requests. Seen in 4 disclosed reports; 2 confirmed bounties: $700 and $10,000; latest 2021-05-31. Updated 2026-10-24._

## How it works
A redirect or return-URL parameter is meant to send users only to trusted destinations. The check that enforces this compares the target against a trusted value using a weak test: a substring `contains()`, a glob/pattern match, or a hostname-only comparison. Each of these tests a property that is not the same as "the parsed origin equals a trusted origin." An attacker who controls any part of the URL string, or any host that satisfies the weak test, passes validation and the browser is sent elsewhere.

## Where it shows up
- URL parameters named `return_url`, `return_to`, `redirect_to`, `checkout_url`, `next`, `continue`.
- Validation code using `contains()`, `startsWith()`, regex/glob patterns, or comparing only `host` without scheme and full origin.
- Allowlists that include subdomains which themselves host user-controlled redirect config (store URL redirects, custom 404s, account-forwarding endpoints).
- Cookies or params holding a URL (e.g. an avatar URL) checked by substring.
- Browser features applying allowlists to redirect targets with non-standard pattern matching [E1](https://bugbountylibrary.com/r/blog%3Ablog-lbherrera-me-posts-appcache-forgotten-tales.md).

## How to review
Find every place a user-supplied URL becomes a redirect target. The invariant: parse the target into a full origin (scheme + host + port), then require exact equality against a fixed allowlist of origins. Reject anything that fails to parse. Do not accept substring, prefix, glob, or hostname-only matches. For each allowlisted host, ask whether that host can itself redirect off-site to attacker-chosen destinations; if so it is not a safe terminal. Confirm the final hop is the trusted origin, not an intermediate that forwards.

## Variants seen
- Substring `contains()` check on a cookie URL, bypassed by prepending an attacker server while keeping the required substring [E2](https://bugbountylibrary.com/r/h1%3A1067809.md).
- Trusted subdomain whose user-configurable redirects complete the hop to an external site [E3](https://bugbountylibrary.com/r/h1%3A159522.md).
- Trusted host with an endpoint that forwards to an attacker-controlled account, defeating an interstitial trust decision [E4](https://bugbountylibrary.com/r/h1%3A111968.md).
- Non-standard glob/pattern matching on an allowlist that also governs redirect targets, turning it into a per-character oracle [E1](https://bugbountylibrary.com/r/blog%3Ablog-lbherrera-me-posts-appcache-forgotten-tales.md).

## Why fixes fail
E4 shows a prior open-redirect report declined as unfixed, then bypassed by routing through a trusted host's forwarding endpoint. Blocking one hostname is insufficient when other trusted hosts forward onward.

## Impact and severity
Leaked CSRF tokens and usernames [E1](https://bugbountylibrary.com/r/blog%3Ablog-lbherrera-me-posts-appcache-forgotten-tales.md), leaked agent IPs and forced logout [E2](https://bugbountylibrary.com/r/h1%3A1067809.md), and redirect to attacker sites via trusted-domain pivots [E3](https://bugbountylibrary.com/r/h1%3A159522.md)[E4](https://bugbountylibrary.com/r/h1%3A111968.md). Severity rises when the redirect carries tokens or when the trusted hop defeats a security interstitial.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Ablog-lbherrera-me-posts-appcache-forgotten-tales.md
- E2: https://bugbountylibrary.com/r/h1%3A1067809.md
- E3: https://bugbountylibrary.com/r/h1%3A159522.md
- E4: https://bugbountylibrary.com/r/h1%3A111968.md
