← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Open Redirect

Security CWE-601 OWASP A1:2021 CVSS 6.1 PHP 5.0+ Beginner
debt(d5/e3/b3/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep and psalm — both specialist SAST tools — as the automated detection path. The code_pattern shows these tools target specific taint flows (e.g. header('Location: '.$_GET[)), which means common linters won't catch it by default, but a configured semgrep ruleset or psalm taint analysis will. Not visible at compile time and not caught by default linters, so d5 is the right anchor.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix says to use an allowlist of permitted destinations or internal path-only redirects — this is a contained change at the redirect call site(s), typically replacing one pattern with a safer validated alternative. It doesn't require a cross-cutting refactor, but it's more than a single one-line swap if multiple redirect points exist, hence e3 rather than e1.

b3 Burden Structural debt — long-term weight of choosing wrong

Closest to 'localised tax' (b3). The applies_to scope is web context only, and the fix is concentrated at redirect call sites within individual request-handling code. It doesn't shape the overall architecture or impose a persistent tax on every future feature, but each developer touching URL-handling code must be aware of the pattern. b3 is appropriate — one component pays, the rest of the codebase is largely unaffected.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states that developers treat open redirects as low severity because 'they just redirect users,' missing that they are routinely chained into phishing, OAuth bypass, and SSRF attacks. The common_mistakes reinforce this: strpos() domain validation and protocol-relative URLs both appear safe but are trivially bypassed. This contradicts how developers typically reason about redirect severity, warranting t7.

About DEBT scoring →

Also Known As

unvalidated redirect open redirector URL redirect vulnerability

TL;DR

A redirect destination taken from user input can send victims to attacker-controlled sites, enabling phishing.

Explanation

An open redirect lets an attacker craft a URL on your trusted domain that immediately redirects to a malicious site. Because the initial URL appears legitimate (e.g. yourbank.com/login?next=evil.com), victims are more likely to click it. Attackers use open redirects in phishing campaigns and OAuth token theft. Mitigation: validate redirect targets against an explicit allowlist of permitted paths, or restrict to relative URLs only.

How It's Exploited

GET /login?next=https://evil.com
# After login, user is silently redirected to phishing site

Common Misconception

Open redirects are low severity because they just redirect users. They are routinely chained with phishing (trusted domain in the URL), OAuth redirect_uri bypass, and SSRF — making them a common link in higher-severity attack chains.

Why It Matters

An open redirect lends your trusted domain to phishing campaigns — the victim sees a legitimate URL before being redirected to a malicious site.

Common Mistakes

  • Using $_GET['redirect'] or $_GET['next'] directly in header('Location: ...') without validation.
  • Validating that the URL starts with your domain using strpos() — trivially bypassed with your-domain.evil.com.
  • Allowing protocol-relative URLs (//evil.com) which browsers interpret as full redirects.
  • Forgetting that JavaScript redirects (window.location) are equally exploitable if fed from user input.

Code Examples

✗ Vulnerable
// Redirects to any URL the user provides
$url = $_GET['next'];
header('Location: ' . $url);
✓ Fixed
// Allowlist approach
$allowed = ['/dashboard', '/profile', '/orders'];
$next    = $_GET['next'] ?? '/dashboard';
$target  = in_array($next, $allowed, true) ? $next : '/dashboard';
header('Location: ' . $target);

// Or validate it's the same host
$parsed = parse_url($next);
if (!empty($parsed['host'])) { $next = '/dashboard'; } // reject absolute URLs

Added 15 Mar 2026
Edited 22 Mar 2026
Views 46
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W 1 ping T 0 pings F 1 ping S 3 pings S 1 ping M 1 ping T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 1 ping M 0 pings T 2 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 1 ping T 0 pings W
No pings yet today
Ahrefs 1
Amazonbot 10 Ahrefs 6 Scrapy 5 Bing 4 SEMrush 4 Google 3 ChatGPT 2 Claude 2 Perplexity 1 Meta AI 1
crawler 33 crawler_json 5
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Never redirect to a URL taken from user input; use an allowlist of permitted destinations or internal path-only redirects
📦 Applies To
PHP 5.0+ web
🔗 Prerequisites
🔍 Detection Hints
header('Location: '.$_GET[ or redirect($_GET['url'] or redirect($_GET['next']
Auto-detectable: ✓ Yes semgrep psalm
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-601


✓ schema.org compliant