Skip to content

Reject leading backslash in post-login redirect target - #7777

Closed
winebarrel wants to merge 1 commit into
getredash:masterfrom
winebarrel:fix-backslash-open-redirect
Closed

Reject leading backslash in post-login redirect target#7777
winebarrel wants to merge 1 commit into
getredash:masterfrom
winebarrel:fix-backslash-open-redirect

Conversation

@winebarrel

@winebarrel winebarrel commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Problem

_is_safe_next_url() treats \evil.com as a safe post-login redirect target. It normalizes backslash to slash before validating, so \evil.com becomes /evil.com and passes as a relative path.

test_backslash_redirect_rejected (added in 9e66f81) expects \evil.com to be rejected. As a result, master's backend-unit-tests have been failing since that commit.

FAILED tests/test_authentication.py::TestRedirectToUrlAfterLoggingIn::test_backslash_redirect_rejected
>       self.assertEqual(response.location, "./")
E       AssertionError: '\\evil.com' != './'

Fix

Reject any redirect target that starts with a backslash. A valid on-site path always starts with a forward slash or a path segment, never a backslash, so this does not affect legitimate redirects. It also covers \\evil.com and \/evil.com, which browsers read as //evil.com.

Test

All redirect cases in TestRedirectToUrlAfterLoggingIn pass, including the previously failing \evil.com, with no change to valid paths such as //localhost/queries -> /queries.

Review in cubic

_is_safe_next_url() normalizes backslash to slash before validating, so
"\evil.com" becomes "/evil.com" and passes as a safe relative path. The
test_backslash_redirect_rejected test (added in 9e66f81) expects it to be
rejected, so master's backend unit tests have failed since that commit.

Reject any target that starts with a backslash. A valid on-site path never
starts with one. This also covers \\evil.com and \/evil.com, which browsers
read as //evil.com.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@greptile-apps

greptile-apps Bot commented Aug 1, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes an open-redirect bypass in _is_safe_next_url where a \evil.com redirect target passed validation because the function's backslash-normalization loop converted it to /evil.com before inspection, making it look like a safe relative path. The one-line early-reject guard (url.startswith("\\")) is added before the normalization loop.

  • Root cause fixed: \evil.com → after replace("\\", "/") becomes /evil.com (no netloc, no scheme) → previously allowed; now caught by the leading-backslash check.
  • Coverage: Also rejects \\evil.com and \/evil.com (both start with \), which browsers interpret as protocol-relative //evil.com.
  • No regression: Legitimate paths start with / or a path segment, never \, and the previously failing test test_backslash_redirect_rejected now passes.

Confidence Score: 5/5

Safe to merge — the change is a minimal, targeted guard that closes a confirmed open-redirect bypass without affecting any legitimate redirect paths.

The fix is a single early-return check added before the existing normalization loop. The logic is correct: valid on-site paths never start with a backslash, so the guard cannot block legitimate redirects. The previously failing test test_backslash_redirect_rejected now passes, and get_next_path already falls back to './' for any input that fails _is_safe_next_url and has no netloc, so the end-to-end behavior is sound.

Files Needing Attention: No files require special attention.

Important Files Changed

Filename Overview
redash/authentication/init.py Adds a leading-backslash early-reject guard to _is_safe_next_url, correctly fixing an open-redirect bypass where \evil.com normalized through the existing replace loop to /evil.com and passed validation.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["next= URL from query string"] --> B{"Empty or blank?"}
    B -- Yes --> Z["Return './'"]
    B -- No --> C{"Leading control char?"}
    C -- Yes --> Z
    C -- No --> D{"Starts with backslash?\n(NEW GUARD)"}
    D -- Yes --> Z
    D -- No --> E{"Check original URL\n& backslash-normalized URL"}
    E -- "Has netloc / bad scheme / starts with ///" --> Z
    E -- Clean --> F["_is_safe_next_url → True"]
    F --> G["Return URL as-is"]
    F --> H{"URL not safe?\nget_next_path fallback"}
    H -- "No netloc in urlsplit" --> Z
    H -- "Has netloc + http(s)" --> I["Extract path component only"]
    I --> G
Loading

Reviews (1): Last reviewed commit: "Reject leading backslash in post-login r..." | Re-trigger Greptile

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Re-trigger cubic

@winebarrel

Copy link
Copy Markdown
Contributor Author

dup #7774

@winebarrel winebarrel closed this Aug 1, 2026
@winebarrel
winebarrel deleted the fix-backslash-open-redirect branch August 1, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant