fix(execute): reject only cross-site session execution (CSRF guard)#5068
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview A new helper Reviewed by Cursor Bugbot for commit 79160d7. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR re-lands the session-cookie CSRF guard on
Confidence Score: 4/5Safe to merge — the guard is narrowly scoped to session-authenticated execute calls and the same-site allowance is correctly preserved to avoid repeating the staging regression. The core logic is a single-line header comparison with thorough tests. The only non-trivial design point is that session validation runs before the CSRF check, meaning a valid session cookie is still looked up even for requests the guard will ultimately reject — a minor efficiency trade-off, not a correctness issue. No files require special attention; the route change is small and well-isolated. Important Files Changed
Sequence DiagramsequenceDiagram
participant Browser
participant ExecuteRoute as POST /execute
participant HybridAuth as checkHybridAuth
participant CSRFGuard as isCrossSiteSessionRequest
participant WorkflowAuthz as authorizeWorkflow
Browser->>ExecuteRoute: POST (with session cookie)
ExecuteRoute->>HybridAuth: checkHybridAuth(req)
HybridAuth-->>ExecuteRoute: "{ success, authType, userId }"
alt "authType === SESSION"
ExecuteRoute->>CSRFGuard: isCrossSiteSessionRequest(req)
alt Sec-Fetch-Site: cross-site
CSRFGuard-->>ExecuteRoute: true
ExecuteRoute-->>Browser: 403 Access denied
else "same-origin | same-site | none | absent"
CSRFGuard-->>ExecuteRoute: false
ExecuteRoute->>WorkflowAuthz: authorizeWorkflowByWorkspacePermission(...)
WorkflowAuthz-->>ExecuteRoute: "{ allowed, workflow }"
ExecuteRoute-->>Browser: 200/202 execution result
end
else API_KEY / INTERNAL_JWT / PUBLIC_API
Note over ExecuteRoute: CSRF guard skipped
ExecuteRoute->>WorkflowAuthz: authorizeWorkflowByWorkspacePermission(...)
WorkflowAuthz-->>ExecuteRoute: "{ allowed, workflow }"
ExecuteRoute-->>Browser: 200/202 execution result
end
Reviews (1): Last reviewed commit: "fix(execute): reject only cross-site ses..." | Re-trigger Greptile |
Summary
POST /api/workflows/[id]/execute, corrected after fix(execute): block cross-origin session-authenticated workflow runs #5062 was reverted (Revert "fix(execute): block cross-origin session-authenticated workfl… #5065).Sec-Fetch-Site: cross-site—same-origin,same-site,none, and absent are all allowed.AuthType.SESSION); API-key / public-API / internal-JWT callers are untouched. Returns the standardAccess denied403.Why #5062 was reverted, and what changed
#5062 rejected anything that wasn't
same-origin(it 403'dsame-site). On a multi-subdomain deployment — e.g. hitting the app atwww.staging.sim.aiwhile the canonical origin isstaging.sim.ai— a legitimate Run POST issame-site, so it got 403'd and Run broke. Thatsame-sitetightening came from a review suggestion; it's unsafe for this topology.This version accepts
same-siteso sibling-subdomain Run works, while still blocking real cross-site CSRF (Sec-Fetch-Site: cross-siteis browser-set and cannot be forged by page JS). The brittleOrigin/getBaseUrl()fallback is removed entirely.Scope / what this is not
CSRF protection only. It does not defend against a non-browser client that forges headers directly (no header check can); that surface is covered by the credit and execution rate-limit gates.
Type of Change
Testing
same-siteallowed) + route tests: a cross-site request → 403, and asame-siteRun → 202 (the exact regression that broke staging)origin/stagingcode:bun run check:api-validation:strictpassed,tsc --noEmitclean, biome cleanChecklist