fix(uploads): gate execution-context uploads behind write/admin permission by waleedlatif1 · Pull Request #5403 · simstudioai/sim · GitHub
Skip to content

fix(uploads): gate execution-context uploads behind write/admin permission#5403

Closed
waleedlatif1 wants to merge 110 commits into
stagingfrom
worktree-deepsec-fresh
Closed

fix(uploads): gate execution-context uploads behind write/admin permission#5403
waleedlatif1 wants to merge 110 commits into
stagingfrom
worktree-deepsec-fresh

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • The multipart-upload fallback route (/api/files/upload) had no workspace-permission check for execution-context uploads, while the primary presigned-upload route (/api/files/presigned) already requires write/admin for the same upload type.
  • Added the same write/admin gate to the fallback route's execution branch, and now require workspaceId (in addition to workflowId/executionId) before proceeding, matching the presigned route's validation.

Note: self-hosted deployments without cloud storage configured will now require write/admin workspace permission for execution-context uploads via this fallback path, matching the existing requirement on the primary presigned-upload path.

Type of Change

  • Bug fix

Testing

  • Added 5 new tests covering: missing workspaceId, read-only member rejected, no-permission member rejected, write-permission member allowed, admin-permission member allowed.
  • bun run vitest run app/api/files/upload/route.test.ts — 19/19 passing.
  • bun run check:api-validation passes.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

waleedlatif1 and others added 30 commits April 3, 2026 23:30
…ership workflow edits via sockets, ui improvements
…ration, signup method feature flags, SSO improvements
* feat(posthog): Add tracking on mothership abort (#4023)

Co-authored-by: Theodore Li <theo@sim.ai>

* fix(login): fix captcha headers for manual login  (#4025)

* fix(signup): fix turnstile key loading

* fix(login): fix captcha header passing

* Catch user already exists, remove login form captcha
…nts, secrets performance, polling refactors, drag resources in mothership
…endar triggers, docs updates, integrations/models pages improvements
…mat, logs performance improvements

fix(csp): add missing analytics domains, remove unsafe-eval, fix workspace CSP gap (#4179)
fix(landing): return 404 for invalid dynamic route slugs (#4182)
improvement(seo): optimize sitemaps, robots.txt, and core web vitals across sim and docs (#4170)
fix(gemini): support structured output with tools on Gemini 3 models (#4184)
feat(brightdata): add Bright Data integration with 8 tools (#4183)
fix(mothership): fix superagent credentials (#4185)
fix(logs): close sidebar when selected log disappears from filtered list; cleanup (#4186)
v0.6.46: mothership streaming fixes, brightdata integration
waleedlatif1 and others added 22 commits June 10, 2026 13:20
…ration, smooth streaming, security hardening, db fixes
…x, db migrations from ci, docs updates, read replicas

v0.7.3: jira oauth scope fix, read-replica client, table wire data fix, db migrations from ci, docs updates, read replicas
…uting, trigger.dev, temporal, latex, quartr, brex, convex integrations
…richment providers, deepseek models, db performance
…nce, file sharing, scheduled tasks granularity
…t harness, sakana fugu provider

v0.7.13: pii redaction, react query frontend refactor, pi coding agent harness, sakana fugu provider
…ix, settings overhaul, thrive learning integration
…extension, workspace forking, slack trigger extension, new README
…ssion

Fallback multipart upload route (/api/files/upload) had no workspace
permission check for execution-context uploads, unlike the primary
presigned-upload route which requires write/admin. Mirror that gate
so both paths enforce the same access control.
@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

@cursor

cursor Bot commented Jul 3, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Tightens authorization on a file-upload API path (execution context); read-only or missing-permission users lose a previously allowed fallback upload route, which is intentional but behavior-changing for self-hosted/local storage.

Overview
Closes a permission gap on the multipart fallback upload route (POST /api/files/upload): execution-context uploads now match the presigned path by requiring workspaceId alongside workflowId and executionId, and by checking getUserEntityPermissions so only write or admin workspace members can upload (403 otherwise).

The execution branch no longer passes an empty workspaceId when it was omitted; uploads are rejected up front with a validation error instead of proceeding.

Tests add an Execution Context Permission Gate suite (missing workspaceId, read/null permission denied, write/admin allowed) with mocks for uploadExecutionFile.

Reviewed by Cursor Bugbot for commit fe82691. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR closes a permission gap where the multipart-upload fallback route (/api/files/upload) accepted execution-context uploads from any authenticated user, while the primary presigned-upload route (/api/files/presigned) already enforced write/admin workspace permission for the same operation.

  • Adds a workspaceId requirement and a write/admin permission gate to the execution branch of the fallback upload route, mirroring the existing check in the presigned route.
  • Fixes the prior workspaceId || '' fallback that silently accepted requests with no workspace context by throwing a 400 instead.
  • Adds 5 targeted tests covering the missing-workspaceId, read-only, no-permission, write, and admin cases; all 19 route tests pass.

Confidence Score: 5/5

The change is a targeted security hardening that brings the fallback upload route in line with the presigned route; no existing functionality is removed and the added permission check cannot be bypassed.

Both changed files are small and self-contained. The permission logic directly mirrors the already-reviewed presigned route. The new validation eliminates the workspaceId || '' silent no-op that previously allowed any authenticated user to reach uploadExecutionFile. Test coverage is comprehensive for the new branch.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/app/api/files/upload/route.ts Adds workspaceId validation and write/admin permission gate to the execution context branch, matching the presigned route; the fix is well-scoped and logically consistent with peer contexts.
apps/sim/app/api/files/upload/route.test.ts Adds 5 new tests covering the full permission matrix for execution uploads; mocks are correctly scoped and assertions cover both rejection and success paths.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client
    participant FallbackRoute as /api/files/upload
    participant Auth as getSession()
    participant Perms as getUserEntityPermissions()
    participant Storage as uploadExecutionFile()

    Client->>FallbackRoute: "POST (context=execution, workspaceId, workflowId, executionId, file)"
    FallbackRoute->>Auth: getSession()
    Auth-->>FallbackRoute: session or null
    alt No session
        FallbackRoute-->>Client: 401 Unauthorized
    end

    FallbackRoute->>FallbackRoute: Validate form fields (Zod)
    alt workflowId / executionId / workspaceId missing
        FallbackRoute-->>Client: 400 Invalid Request
    end

    FallbackRoute->>Perms: getUserEntityPermissions(userId, 'workspace', workspaceId)
    Perms-->>FallbackRoute: "'read' | 'write' | 'admin' | null"
    alt "permission != 'write' and != 'admin'"
        FallbackRoute-->>Client: 403 Write or Admin access required
    end

    FallbackRoute->>Storage: "uploadExecutionFile({workspaceId, workflowId, executionId}, buffer, ...)"
    Storage-->>FallbackRoute: userFile
    FallbackRoute-->>Client: "200 { id, name, url, ... }"
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client
    participant FallbackRoute as /api/files/upload
    participant Auth as getSession()
    participant Perms as getUserEntityPermissions()
    participant Storage as uploadExecutionFile()

    Client->>FallbackRoute: "POST (context=execution, workspaceId, workflowId, executionId, file)"
    FallbackRoute->>Auth: getSession()
    Auth-->>FallbackRoute: session or null
    alt No session
        FallbackRoute-->>Client: 401 Unauthorized
    end

    FallbackRoute->>FallbackRoute: Validate form fields (Zod)
    alt workflowId / executionId / workspaceId missing
        FallbackRoute-->>Client: 400 Invalid Request
    end

    FallbackRoute->>Perms: getUserEntityPermissions(userId, 'workspace', workspaceId)
    Perms-->>FallbackRoute: "'read' | 'write' | 'admin' | null"
    alt "permission != 'write' and != 'admin'"
        FallbackRoute-->>Client: 403 Write or Admin access required
    end

    FallbackRoute->>Storage: "uploadExecutionFile({workspaceId, workflowId, executionId}, buffer, ...)"
    Storage-->>FallbackRoute: userFile
    FallbackRoute-->>Client: "200 { id, name, url, ... }"
Loading

Reviews (1): Last reviewed commit: "fix(uploads): gate execution-context upl..." | Re-trigger Greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@waleedlatif1 waleedlatif1 deleted the worktree-deepsec-fresh branch July 4, 2026 03:05
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.

4 participants