agentleFS
mahumadadmahumadad/quarry/skills/hunt/open-redirect/SKILL.md

open-redirect

Skill1 starsChanged 12 days agoMITView on GitHub

Hunt for open redirect: parameter-based redirects, header-based redirects (Location injection), and meta-refresh/JS-based redirect sinks. Use when a URL/param controls post-action navigation — `?next=`, `?returnUrl=`, `?redirect=`, OAuth `redirect_uri`, logout/SSO landing pages, "continue to" links. Keywords: open redirect, unvalidated redirect, redirect_uri, returnUrl, next param, location header injection, meta refresh, javascript window.location, oauth redirect_uri bypass, phishing pivot. Do NOT use for redirects that are purely internal/relative-path-only with no way to point off-domain (not exploitable — note as N/A). Do NOT use for SSRF where the *server* follows the redirect — that's ssrf; this skill is about the *victim's browser* being redirected.

10 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use path-traversal and command-injection.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • langbyyiSkill

    path-traversal

    Path traversal and LFI playbook. Use when file paths, download endpoints, include operations, archive extraction, or wrapper behavior may expose filesystem control.

    Also in 4 projects that use this

  • blacklanternsecuritySkill

    command-injection

    Guide OS command injection exploitation during authorized penetration testing.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

5 rules. 0 are common, 1 is distinctive, and 4 are very specific to this project.

  • 0

    Common

    Most of the 7 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Check the Location header of the resulting redirect response (or final destination if curl follows with -L) for evil.test.

    line 52
  2. Very specific:

    Filter/validation bypass variants: when a naive check blocks plain https://evil.test (common checks: "starts with http", "contains target …

    line 55
  3. Very specific:

    Header-based (Location injection) check: when the redirect target is built from a header value (e.g., Referer, a custom header) rather than …

    line 69
  4. Very specific:

    If step confirms the authorization flow completes and the code/token lands on evil.test (via the chained open-redirect page), this is a …

    line 98
  5. Distinctive:

    Before declaring this finding complete, probe these escalation paths:

    line 162

“Common” is measured: kept by at least 6 in 10 of the 7 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Signals

  • Params named next, redirect, redirect_uri, return, returnUrl, continue, url, dest, target, goto, callback on login/logout flows, OAuth/SSO, link-tracking/ email-click endpoints.
  • OAuth 2.0/OIDC flows where redirect_uri validation seems loose (accepts any URI under a registered domain rather than exact match, or doesn't validate at all).
  • Location header in a 3xx response built from user input.
  • Client-side redirects: window.location = getParam('next'), meta-refresh tags with a dynamic URL.
  • Link-shortener or "you are leaving this site" interstitial features.

Prerequisites

  • An identified redirect-controlling parameter or OAuth flow.
  • For OAuth-specific testing: the app's registered redirect_uri value(s) to compare against, and an understanding of exact-match vs. prefix-match vs. no-match validation behavior.

Methodology

  1. Baseline and direct absolute-URL test:
    curl -sI "https://target/login?next=/dashboard"              # baseline relative, expected
    curl -sI "https://target/login?next=https://evil.test"        # absolute external
    curl -sI "https://target/login?next=//evil.test"               # protocol-relative
    curl -sI "https://target/login?next=https:evil.test"           # missing-slash variant
    Check the Location header of the resulting redirect response (or final destination if curl follows with -L) for evil.test.
  2. Filter/validation bypass variants when a naive check blocks plain https://evil.test (common checks: "starts with http", "contains target domain somewhere"):
    curl -sI "https://target/login?next=https://target.com@evil.test"      # userinfo trick
    curl -sI "https://target/login?next=https://evil.test/target.com"      # path trick
    curl -sI "https://target/login?next=https://evil.target.com"           # subdomain-confusion
    curl -sI "https://target/login?next=https://target.com.evil.test"      # domain-confusion
    curl -sI "https://target/login?next=/%2F%2Fevil.test"                  # encoded double-slash
    curl -sI "https://target/login?next=/\\evil.test"                      # backslash (browser
                                                                            #   treats as //)
    curl -sI "https://target/login?next=https:/evil.test"                 # single slash
    curl -sI "https://target/login?next=%09https://evil.test"             # tab-char smuggle
  3. Header-based (Location injection) check when the redirect target is built from a header value (e.g., Referer, a custom header) rather than a query param:
    curl -sI "https://target/logout" -H "Referer: https://evil.test"
  4. Meta-refresh / JS-sink confirmation — static analysis of client JS plus a real-browser check, since curl won't execute JS redirects:
    curl -s https://target/app.js | grep -nE "window\.location|location\.href|location\.replace|meta.*refresh"
    Then manually load https://target/page?next=https://evil.test in a browser and confirm actual navigation occurs (address bar changes to evil.test).
  5. OAuth redirect_uri validation bypass — the highest-impact open-redirect variant, since it can leak authorization codes/tokens to an attacker domain:
    # exact-registered value, baseline
    curl -s "https://target/oauth/authorize?client_id=CID&redirect_uri=https://target/callback&response_type=code"
    
    # prefix/path-append bypass
    curl -s "https://target/oauth/authorize?client_id=CID&redirect_uri=https://target/callback/../evil&response_type=code"
    curl -s "https://target/oauth/authorize?client_id=CID&redirect_uri=https://target/callback.evil.test&response_type=code"
    curl -s "https://target/oauth/authorize?client_id=CID&redirect_uri=https://target/callback%2F@evil.test&response_type=code"
    
    # open redirect endpoint ON the trusted domain used AS the redirect_uri (chains an
    # already-found open redirect into OAuth token theft)
    curl -s "https://target/oauth/authorize?client_id=CID&redirect_uri=https://target/login?next=https://evil.test&response_type=code"
    If step confirms the authorization flow completes and the code/token lands on evil.test (via the chained open-redirect page), this is a critical-severity finding — document the full redirect chain.
  6. Automated sweep across many params/paths:
    ffuf -w redirect_params.txt -u "https://target/login?FUZZ=https://evil.test" \
      -mr "evil\.test" -o redirect_sweep.json -of json
    nuclei -l urls.txt -tags redirect -o nuclei_redirect.txt

Tooling

  • curl -I/-L — primary manual technique; always inspect the Location header directly rather than relying on curl's auto-follow, to see exactly what the server sent.
  • Browser devtools — required for JS/meta-refresh-sink confirmation.
  • ffuf/nuclei -tags redirect — breadth sweep.
  • Burp Suite — intercept and modify the actual OAuth flow for the redirect_uri bypass testing.

Root Causes

  • Redirect target taken directly from user input with no allowlist of permitted destinations or paths.
  • Validation implemented as a blocklist/substring check (if not url.startswith("http"), if "evil" not in url) instead of parsing the URL and checking the actual host against an allowlist.
  • OAuth/OIDC redirect_uri validated via prefix/substring match instead of the spec-required exact string match against the registered value.

Validation Gate (minimum proof)

  • A request to the redirect-controlling parameter/flow results in an actual Location header (or confirmed browser navigation for JS-based sinks) pointing to a domain you control, fully outside the target's domain — captured request + response.
  • For OAuth: the full authorization flow completed end-to-end with the authorization code/token actually arriving at the attacker-controlled endpoint — not just a validation error bypassed partway through.

Gotchas

  • Minimum proof, not a live phishing campaign. Point the PoC at a benign test page you control (a simple "redirect confirmed" page); don't build or send actual phishing content as part of this proof.
  • Common N/A: redirect target is validated against a real allowlist and only ever resolves to relative/same-origin paths, with no bypass found after testing the variants in step 2 — legitimate N/A, don't report "the app has a next param" as a finding without a working bypass.
  • Common N/A: the app does redirect to an arbitrary URL, but only after an interstitial warning page the user must explicitly click through ("You are leaving target.com") — this significantly reduces real-world risk; note it as a mitigating factor affecting severity, not as making it a non-finding (the underlying lack of validation is still real).
  • Overclaim trap: a 3xx response with a Location header pointing to your test domain is solid proof; a 200 response that merely contains the string evil.test somewhere in the body (e.g., in an error message echoing the param) is not redirect proof — confirm an actual navigation/redirect occurs.
  • Overclaim trap: OAuth redirect_uri bypass findings are only as severe as what actually reaches the attacker domain — confirm whether it's the authorization code (serious, often exchangeable for a token) or just a harmless post-login landing page (lower severity); state which explicitly.
  • Browser-specific parsing differences matter here (backslash-as-slash normalization varies by browser) — note which browser confirmed the bypass if it's browser-dependent.

Chain Anchors

Before declaring this finding complete, probe these escalation paths:

  1. OAuth redirect_uri abuse — Can the open redirect be used as the redirect_uri in an OAuth/OIDC flow to steal authorization codes or tokens?
  2. Referer leakage — Does navigating through the redirect leak tokens/codes via the Referer header to an attacker-controlled endpoint?
  3. SSRF chaining — Can the redirect be chained into an SSRF primitive elsewhere in the app (a server-side followed redirect)?
  4. Phishing with trusted domain — Does the redirect keep the trusted domain visible in the address bar long enough to be convincing for phishing?

A finding without chain anchor results is INCOMPLETE. Record each anchor as tested/not-applicable/blocked with the reason.

Chains & Compositions

  • Open redirect → OAuth token/code theft → auth-bypass/account takeover (the highest-impact chain for this class — always check whether an open redirect sits inside or near an OAuth flow).
  • Open redirect used to add legitimacy to a phishing link (makes a malicious URL start with the trusted domain) — report as a distinct lower-but-real risk even without a technical token- theft chain.
  • Open redirect + reflected xss on the redirect landing page compounds into a more convincing attack chain — note the combination if both exist on the same flow.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.