Skip to content

fix: keep session material and open redirects out of switchToOrganization - #94

Merged
nicknisi merged 1 commit into
mainfrom
fix/vuln-1244-1264-switch-to-organization
Sep 15, 2026
Merged

nicknisi merged 1 commit into
mainfrom
fix/vuln-1244-1264-switch-to-organization

Conversation

@nicknisi

Copy link
Copy Markdown
Member

Hardens switchToOrganization in src/auth.ts. Two findings, one function, one change.

VULN-1244: session material in action data

The no-returnTo branch returned refreshSession's result verbatim in data(). That serialized accessToken, sealedSession (the iron-sealed blob that wraps the refresh token) and the raw Set-Cookie string into the browser-readable single-fetch .data payload and the SSR hydration HTML. Replaying just the cookie lifted from that body authenticated as the victim.

Fix: return an allowlisted projection of display-safe claims (user, sessionId, organizationId, role, roles, permissions, entitlements, featureFlags, impersonator). The session still travels via the Set-Cookie response header only. This is the same invariant authkitLoader has enforced since CVE-2025-55008 (20102af / 607caac); this branch was missed then.

Allowlist rather than destructure-away so a future field added to refreshSession does not leak by default.

VULN-1264: open redirect via returnTo

The returnTo branch called redirect(returnTo) raw. getSignInUrl / getSignUpUrl already run the same shape of caller-supplied return target through sanitizeReturnPathname; this sink was the inconsistency.

Fix: redirect(sanitizeReturnPathname(returnTo)). Absolute URLs, protocol-relative, backslash, CRLF, and encoded bypasses all redirect to /. Same-origin paths with query and hash pass through unchanged.

Behavior change: a caller passing an absolute same-origin URL (https://myapp.com/dashboard) as returnTo now lands on /. Pass a pathname instead. signOut({ returnTo }) is unchanged; that one is an absolute URL validated against the WorkOS dashboard allowlist.

Verification

  • npm run typecheck, npm run lint, npm run prettier: clean
  • npm test: 181 passed
  • New regression tests fail against the previous auth.ts (8 failures) and pass with this change

Refs VULN-1244, VULN-1264. The Remix twin (VULN-1260, authkit-remix/src/auth.ts) has the identical pattern and is not covered here.

…tion

Two hardening changes to the same helper.

VULN-1244: the no-returnTo branch returned refreshSession's result verbatim
in data(), which serialized accessToken, sealedSession (the iron-sealed blob
wrapping the refresh token) and the raw Set-Cookie string into the
browser-readable single-fetch payload and SSR hydration data. Return an
allowlisted projection of display-safe claims instead; the session still
travels via the Set-Cookie response header only. Same invariant authkitLoader
has enforced since CVE-2025-55008.

VULN-1264: the returnTo branch called redirect(returnTo) raw. Run it through
the package's existing sanitizeReturnPathname so a request-controlled value
cannot produce an off-origin redirect. Rejected values redirect to /.
@linear-code

linear-code Bot commented Sep 15, 2026

Copy link
Copy Markdown

VULN-1244

VULN-1264

@greptile-apps

greptile-apps Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge and consistently applies the repository’s session-boundary and return-path protections.

Summary

This PR hardens switchToOrganization by preventing session material from entering browser-readable action data and validating organization-switch redirect targets.

  • Projects refresh results onto the established display-safe authentication state.
  • Keeps the replacement session exclusively in the Set-Cookie response header.
  • Sanitizes returnTo as an application-relative pathname before redirecting.
  • Adds regression coverage for sensitive response fields, unsafe redirect forms, and valid query/hash preservation.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Organization switch request] --> B[Refresh session for organization]
  B --> C[Extract replacement Set-Cookie]
  C --> D[Project display-safe auth claims]
  D --> E{returnTo supplied?}
  E -- No --> F[Return safe auth data]
  E -- Yes --> G[Sanitize return pathname]
  G --> H[Redirect to local path]
  C --> F
  C --> H
Loading

Reviews (1) · Last reviewed commit: "fix: keep session material and open redi..."

@nicknisi
nicknisi merged commit 900ce8a into main Sep 15, 2026
9 checks passed
@nicknisi
nicknisi deleted the fix/vuln-1244-1264-switch-to-organization branch September 15, 2026 18:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants