Repository navigation
fix(oauth): reject cross-site workspace OAuth launches - #9772
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
[Medium impact] The changes affect the bounded workspace OAuth account-linking and login callback flows. The behavior changes appear safe, but the new test wrapper must use the required shared helper before merging. Findings
SummaryThe PR blocks cross-site workspace OAuth launches before creating a connection draft.
Reviews (3) · Last reviewed commit: "fix(oauth): keep workspace launches out ..." · Reviewed by Greptile |
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
Summary
GET /api/auth/oauth2/authorize?providerId=…&workspaceId=…[&credentialId=…]picked the workspace (and, on reconnect, the credential) from the query alone and created a connect draft on the viewer's session. Session cookies areSameSite=Lax, so a cross-site page could navigate a signed-in user there and link their provider account as a credential in a workspace the attacker shares with them, or rebind an existing credential to the victim's account (CSRF on a state-changing GET)Sec-Fetch-Siteiscross-site, before any draft is created, using the existingisCrossSiteSessionRequesthelper (same gate as workflow execute)draftIdlaunches are unchanged: drafts are bound to the user who created them, and v2 API callers hand those authorization URLs to users from their own originsame-origin),www↔ apex (same-site), and desktop/CLI/address-bar (none) launches still work. A server-side redirect such as/desktop/connectkeeps the attacker's page as the initiator, so the browser still sendscross-site/api/auth/oauth2/authorizecallback, so/login?callbackUrl=<workspace launch>turned the launch into a same-origin request after sign-in. That exception now applies only to OAuth client requests (client_idpresent); a workspace launch callback sends a signed-in user to the app entrycheck-test-typesbaseline for the authorize route test (itsGETcalls now passcreateRouteContext({}))Type of Change
Testing
proxy.test.ts: signed-in/loginwith a workspace-launch callback redirects to the app entry (red before the change); an OAuth client callback still shows the formroute.test.ts: cross-site workspace launch is refused with no draft or link call (red on the pre-fix code, confirmed by reverting the guard); a cross-site launch of the user's own draft still reaches the provider (thesame-site/noneheader matrix is owned bysame-origin.test.ts)bun run --cwd apps/sim testonauthorize/route.test.ts+same-origin.test.ts+proxy.test.ts+app/(auth)suites (107 passed),bun run lint, Phase A generators (no drift); type-check,check:auditsand the full suite run in CIChecklist
test-auditauthoring gate)🤖 Generated with Claude Code