Skip to content

fix(connect): strip Authorization on cross-origin redirects in custom Session#464

Open
tdstein wants to merge 1 commit intomainfrom
fix/session-redirect-cross-origin-auth-strip
Open

fix(connect): strip Authorization on cross-origin redirects in custom Session#464
tdstein wants to merge 1 commit intomainfrom
fix/session-redirect-cross-origin-auth-strip

Conversation

@tdstein
Copy link
Copy Markdown
Collaborator

@tdstein tdstein commented Apr 9, 2026

Summary

The custom Session.post in src/posit/connect/sessions.py manually follows redirects with allow_redirects=False, bypassing requests.SessionRedirectMixin.rebuild_auth. On a cross-origin redirect, the session's Authorization header (Connect API key or bootstrap JWT) was forwarded to the attacker-controlled host named in Location — including protocol-relative //attacker/... resolved via urljoin.

  • Adds a scheme/hostname/port same-origin check before re-dispatching.
  • On a cross-origin hop: strips Authorization from the outgoing headers kwarg and passes auth=None for that request.
  • Rejects redirects whose scheme is not http/https.
  • 307/308 and preserve_post behavior unchanged.

Test plan

  • New tests in tests/posit/connect/test_sessions.py (12 passing):
    • cross-origin strips session-level Authorization
    • cross-origin strips header-kwarg Authorization
    • same-origin preserves Authorization
    • non-http(s) scheme rejected
  • CI

The custom Session.post manually followed redirects and re-dispatched via
self.request without stripping credentials, bypassing requests'
SessionRedirectMixin.rebuild_auth. A malicious or compromised Connect
server could return a Location header pointing to an attacker-controlled
host (including protocol-relative //attacker/... resolved via urljoin)
and receive the Connect API key or bootstrap JWT.

Compare origins (scheme, hostname, port) between the current response
URL and the resolved redirect target; on mismatch, drop any
Authorization header from the outgoing headers kwarg, suppress the
session-level Authorization header, and set auth=None for the next hop.
Also reject redirect schemes other than http/https.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 9, 2026

☂️ Python Coverage

current status: ✅

Overall Coverage

Lines Covered Coverage Threshold Status
2372 2222 94% 0% 🟢

New Files

No new covered files...

Modified Files

File Coverage Status
src/posit/connect/sessions.py 100% 🟢
TOTAL 100% 🟢

updated for commit: 83e0998 by action🐍

tdstein added a commit that referenced this pull request Apr 9, 2026
Replace the hand-rolled redirect loop in Session.post with a minimal
rebuild_method override. Inheriting from requests.SessionRedirectMixin
restores rebuild_auth (strips Authorization on cross-origin hops),
cookie propagation, response.history, TooManyRedirects, proxy rebuild,
and streaming semantics — all of which the previous implementation
silently dropped.

Supersedes the defensive patch in #464.
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