sfw/fix
Open redirect high

Open Redirect (Unvalidated Redirect)

A redirect endpoint takes its destination from a user-controlled parameter with no allow-list, letting attackers bounce visitors off your domain to phishing.

What you see

Open redirect detected
GET /redirect?url=https://evil.example.com
Unvalidated redirect / forward (CWE-601)

What’s actually happening

A security scanner (Burp, ZAP, a pentest report) flags an endpoint like /redirect?url= or /login?next= as an open redirect. The URL starts on your trusted domain, then forwards to wherever the attacker put in the parameter. It gets used in phishing — the link looks like yours, the landing page isn't. It also shows up as a stepping stone in OAuth token-theft and as a way around naive referrer checks.

Common causes

  • A redirect/forward endpoint reads ?url=, ?next=, ?return=, ?dest=, or ?continue= and sends a Location header straight from it with no validation.
  • A login flow preserves a 'return to' URL across auth and trusts it blindly after the user signs in.
  • Validation only checks that the value 'starts with /' but misses //evil.com (protocol-relative) or /\evil.com, both of which browsers treat as off-site.
  • A blocklist approach tries to strip http:// but is bypassed by case, encoding (%2F%2F), or whitespace tricks.
  • An allow-list compares with startswith and gets fooled by evil.com.yourdomain.com or yourdomain.com.evil.com.

How to fix it

  1. Allow-list, don't blocklistValidate the destination against an explicit allow-list of paths or hosts. For internal redirects, only accept relative paths and reject anything with a scheme or host. For external, match the host against a fixed set you control — exact host equality, not startswith/contains.
  2. Reject protocol-relative and backslash formsTreat //evil.com, /\evil.com, and https:evil.com as external. Parse the value with a real URL parser and inspect the resolved host; don't regex it by hand. A leading // is the classic bypass that 'must start with /' checks miss.
  3. Map tokens to URLs instead of passing URLsWhere you can, don't accept a URL at all. Pass an opaque key (?next=dashboard) and look up the real path server-side from a table. The user never controls a URL, so there's nothing to abuse.
  4. Default safe and log rejectsIf validation fails, redirect to a known-safe default (your homepage) rather than echoing the input. Log rejected destinations — a spike of weird hosts is someone probing the endpoint.
  5. Re-scan to confirmRe-run the scanner (ZAP/Burp) against the endpoint with the payloads from the original finding: //evil.com, https://evil.com, /%2F%2Fevil.com. Confirm each lands on your safe default, not the attacker host.

Stop it recurring

Never build a Location header from raw user input — map a token to a server-side path, or validate against an exact-match host allow-list.

Related errors