Skip to content

feat: judge open-redirect flows on the destination a browser resolves - #169

Merged
SizzleUnrlsd merged 2 commits into
mainfrom
feat/url-proof
Sep 26, 2026
Merged

SizzleUnrlsd merged 2 commits into
mainfrom
feat/url-proof

Conversation

@SizzleUnrlsd

Copy link
Copy Markdown
Contributor

Summary

open-redirect now judges each flow on the destination a browser resolves from the target's constant text, with its own criteria. The facts it reads are a proof shared with ssrf, in a new module, coretrace_python.taint.urls. It states what the constant text a URL starts with proves, and nothing more:

  • the fixed origin;
  • whether the path is fixed too;
  • whether the text starts a reference that a browser resolves on the current site;
  • whether the call disables redirects.

Each rule draws its own verdict from it, with no exception coded per CVE.

Closes #168.

Target open-redirect Why
A reference on the current site: / then a character that is not a slash, a backslash, a space or a control character ("/profile/" + id, f"/users/{id}/edit"), ?, #, or a relative path whose first segment ends in the text without a : ("profile/" + id) refuted The browser stays on the site, where any further redirect is the project's own code, analysed on its own.
A fixed absolute host ("https://example.com/" + path) hotspot The browser goes to that host, but the input chooses the path, where that host may redirect again.
Anything else vulnerability, as before "/" + next (//evil.com is another host), "/\\" or "/\t" before the input (a browser takes /\ for // and drops tabs), "https://example.com" + x, "a:b/" or "java" before the input (a scheme may follow), an unknown or imported base, a target built in a helper function.

The SSRF criteria do not carry over. A server-side request to a fixed host may still reach its internal paths, so ssrf keeps a fixed host as a hotspot and refutes only a fixed destination without redirects. A browser on the current site stays within the project's own code.

Design

  • taint/urls.py.
    • UrlProof(text, origin, path_fixed, relative) and url_proof(text) state the proof.
    • flow_url(flow, defs, strings) reads the constant text of the value a flow passes (abstract.strings). A flow reaching its sink in a callee proves nothing.
    • redirects_disabled(arguments) holds when the call passes allow_redirects=False or follow_redirects=False explicitly.
  • ssrf moves onto the shared proof. Its tests, unchanged, pass unchanged.
  • open-redirect refines its verdict through TaintDetector.judge, so the refutation's verdict, which other consumers read, does not change. Its manifest now requires ir.ssa and abstract.module_strings, like ssrf.
  • The requests advisories that need control of the host follow in a separate PR. They will read the same proof.

Corpus

The regression snapshots, which record each verdict, are unchanged. The three open-redirect findings of the corpus redirect to values built without constant text:

Finding Target Verdict
InsecureGram app/redirect.py:11 RedirectResponse(url=target): the whole target is input vulnerability
healthchecks hc/accounts/decorators.py:44 redirect(request.path): a request path of //evil.com would leave the site hotspot, from the refutation
healthchecks hc/accounts/views.py:115 redirect(redirect_url), validated by the project hotspot, from the refutation

Verification

  • New tests only; no existing test file is modified:

    • tests/test_url_proof.py: what each constant text proves, and when redirects are disabled;
    • tests/test_open_redirect_destinations.py: each form, module strings, an imported base, a helper function, Django redirects, and the evidence text.

    The ten tests expecting a refutation or a hotspot failed before the change.

  • pytest: 1274 passed. pytest -m regression: 19 passed, unchanged. ruff check and mypy: clean.

taint.urls states what a URL's constant text proves: a fixed origin, a fixed path, a reference on the current site, and whether a call disables redirects. ssrf now reads it with unchanged verdicts, and open-redirect draws its own: refuted on the current site, a hotspot on a fixed host.
@SizzleUnrlsd SizzleUnrlsd added the enhancement New feature or request label Sep 26, 2026
@SizzleUnrlsd SizzleUnrlsd self-assigned this Sep 26, 2026
@SizzleUnrlsd
SizzleUnrlsd merged commit 9f11b15 into main Sep 26, 2026
10 checks passed
@SizzleUnrlsd
SizzleUnrlsd deleted the feat/url-proof branch September 26, 2026 03:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Precision: open-redirect judges the destination a browser resolves from the target's constant text

1 participant