feat: harden study auth redirects#76
Conversation
## Internal ### Updates & Improvements * Magic-link generation sanitizes and URL-encodes redirect query parameters.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 13 minutes and 49 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
| Filename | Overview |
|---|---|
| pingpong/auth.py | Adds normalize_study_redirect with layered open-redirect defenses (prefix check, ////\ check, control-char check, urlsplit scheme/netloc check) and wires it into generate_auth_link (with proper urlencode) and redirect_with_session_study. |
| pingpong/study/server.py | Applies normalize_study_redirect at all magic-link and auth-callback call sites; fallback RedirectResponse URLs still embed forward without urlencode, which can break query-string parsing for paths containing ? or &. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Incoming redirect param] --> B{normalize_study_redirect}
B --> C{Empty or None?}
C -- Yes --> Z[Return '/']
C -- No --> D{strip and check}
D --> E{Starts with '/'?}
E -- No --> Z
E -- Yes --> F{Starts with '//' or '/backslash'?}
F -- Yes --> Z
F -- No --> G{Contains control chars ord lt 32?}
G -- Yes --> Z
G -- No --> H{urlsplit: has scheme or netloc?}
H -- Yes --> Z
H -- No --> I[Return sanitized path]
I --> J{Usage context}
J --> K[generate_auth_link: urlencode into magic link URL]
J --> L[redirect_with_session_study: config.study_url]
J --> M[Fallback RedirectResponse: embedded raw in query string]
Comments Outside Diff (2)
-
pingpong/study/server.py, line 287-290 (link)forwardnot URL-encoded in fallback redirectforwardis embedded raw into theRedirectResponseURL. If the destination path contains?,&,=, or#(all valid, and not blocked bynormalize_study_redirect), the query string will be malformed and the frontend will parseforwardincorrectly (e.g./courses?tab=1becomes just/courseswith a danglingtab=1param).Use
urlencodeto encodeforwardwhen injecting it as a query parameter value:from urllib.parse import urlencode # example fix for the fallback redirects return RedirectResponse( f"/login?expired=true&{urlencode({'forward': forward})}", status_code=303 )
The same pattern applies at lines 290, 354, and 357.
-
pingpong/study/server.py, line 165-172 (link)Redundant double normalization
safe_forwardis already the result ofnormalize_study_redirect(body.forward). It is then passed asredirect=safe_forwardtogenerate_auth_link, which internally callsnormalize_study_redirect(redirect)again (seeauth.pyline 165). Normalizing twice is harmless but unnecessary. The same applies atlogin_as(line 209) and theauth/auth_adminendpoints wheredestandforwardare each independently derived from the same already-validated query param.You can remove the pre-normalization in
login_magicandlogin_as(sincegenerate_auth_linkalready handles it), or remove the normalization insidegenerate_auth_linkand rely entirely on the call-site to sanitize before calling.
Reviews (1): Last reviewed commit: "Lint" | Re-trigger Greptile
|
@claude review |
Internal
Updates & Improvements