Skip to content

fix(files): authorize presigned upload contexts per type - #6175

Merged
waleedlatif1 merged 1 commit into
stagingfrom
fix/presigned-upload-context-authz
Aug 2, 2026
Merged

fix(files): authorize presigned upload contexts per type#6175
waleedlatif1 merged 1 commit into
stagingfrom
fix/presigned-upload-context-authz

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

  • POST /api/files/presigned/batch validated its type param against the shared 7-value upload enum but only authorized knowledge-base, so any authenticated user could mint an S3 presigned PUT into workspace-logos/, profile-pictures/, execution/, mothership/, chat/ and copilot/ — objects then served unauthenticated from the app origin with a one-year public cache
  • Batch presign now accepts knowledge-base only (its sole client and its sole authorizable context) and always requires a workspaceId the caller has write/admin on before any URL is minted
  • POST /api/files/presigned had the same class of gap for chat: no authorization predicate, no content-type restriction, no client. Dropped it — every remaining context there has a per-context predicate (copilot self-scoped + type-restricted, profile-pictures self-scoped + image-only, mothership/execution workspace write, workspace-logos workspace admin, knowledge-base workspace write)
  • Both allowlists moved into lib/api/contracts/storage-transfer.ts so the enum that is enforced and the one that is documented can't drift apart again — that drift was the root cause

Type of Change

  • Bug fix (security)

Testing

  • New app/api/files/presigned/batch/route.test.ts: 401 unauthenticated, 400 for each of the six refused contexts with no URL minted, 400 missing workspaceId, 403 for read/no access, authz enforced ahead of the local-storage fallback, file-type rejection before minting, and the authorized happy path
  • Added a regression test on the single route asserting type=chat is rejected without minting
  • Verified both suites go red when the fix is reverted (6 batch failures, 1 single-route failure)
  • app/api/files + lib/uploads: 449 tests passing; tsc -p apps/sim clean; bun run check:api-validation passed

Not included

Per-user upload quota / billing attribution for presign issuance. With authorization restored, only workspace members with write access can mint these URLs, so metering is a separate billing feature rather than part of this fix.

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)

The batch presign endpoint validated its type param against the shared
seven-value upload enum while only authorizing knowledge-base, so any
authenticated user could mint an S3 presigned PUT into workspace-logos,
profile-pictures, execution, mothership, chat and copilot prefixes —
objects that are then served unauthenticated from the app origin with a
one-year public cache. The single presign endpoint had the same gap for
chat, which has no authorization predicate and no client.

- Batch presign now accepts only knowledge-base, and always requires a
  workspaceId the caller has write/admin on before anything is minted
- Single presign drops chat from its accepted contexts; every remaining
  context has a per-context predicate
- Both allowlists live in the contract module so the enforced enum and
  the documented one cannot drift apart again
@vercel

vercel Bot commented Aug 2, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 2, 2026 12:40am

Request Review

@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

PR Summary

High Risk
This fixes unauthorized direct-to-bucket writes via presigned URLs—a critical storage/auth issue. Behavior change may break any client still requesting batch presign or single presign for disallowed type values (e.g. chat).

Overview
Closes a security gap where presigned PUT URLs could be minted for storage contexts that were never properly authorized. Batch presign now accepts only knowledge-base, always requires workspaceId, validates file types, and checks write/admin workspace permission before minting URLs or returning the local-storage fallback. Single presign drops chat from the allowed type values (no auth path); remaining contexts stay on their existing per-type checks.

storage-transfer introduces separate presignedUploadTypes and batchPresignedUploadTypes enums so documented allowlists match what each route enforces, instead of sharing a broad upload enum that drifted from authorization logic.

Tests add full coverage for the batch route (401, rejected contexts, missing params, 403, happy path, fallback) and a regression that type=chat on single presign is rejected without minting.

Reviewed by Cursor Bugbot for commit 999b80d. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR closes unauthorized presigned-upload paths by defining endpoint-specific upload-context schemas and requiring workspace write access for batch knowledge-base uploads.

  • Restricts batch presigning to knowledge-base uploads and records workspace ownership after authorization.
  • Removes the unauthorizable chat context from single-file presigning.
  • Adds regression coverage for authentication, workspace permissions, invalid contexts, file validation, fallback behavior, and successful uploads.

Confidence Score: 5/5

The PR appears safe to merge with no actionable regressions identified in the changed upload authorization paths.

The endpoint-specific allowlists match all repository callers, workspace authorization occurs before batch URL issuance or fallback, and the removed profile-picture session check remains enforced by the route-level authentication guard.

Important Files Changed

Filename Overview
apps/sim/app/api/files/presigned/batch/route.ts Restricts batch uploads to knowledge-base files, requires workspace write authorization, and consistently records ownership for generated keys.
apps/sim/app/api/files/presigned/route.ts Uses the narrowed single-upload context schema so chat is rejected while each remaining context follows its existing authorization and validation path.
apps/sim/lib/api/contracts/storage-transfer.ts Introduces endpoint-specific upload-context enums and reuses the single-upload enum in the documented query contract.
apps/sim/app/api/files/presigned/batch/route.test.ts Adds comprehensive regression tests covering authentication, authorization, context and file validation, storage fallback, and ownership metadata.
apps/sim/app/api/files/presigned/route.test.ts Replaces obsolete chat success cases and verifies that the unauthorizable chat context cannot mint a URL.

Sequence Diagram

sequenceDiagram
  participant Client
  participant Route as Presigned Upload Route
  participant Auth as Session / Workspace Auth
  participant Storage as Object Storage
  participant Metadata as File Metadata
  Client->>Route: POST upload request with context
  Route->>Auth: Validate session
  Auth-->>Route: Authenticated user
  Route->>Route: Validate endpoint-specific context
  alt Batch knowledge-base upload
    Route->>Auth: Check workspace write/admin access
    Auth-->>Route: Authorized
  end
  Route->>Storage: Mint presigned upload URL
  Storage-->>Route: URL and object key
  opt Knowledge-base upload
    Route->>Metadata: Record workspace ownership
  end
  Route-->>Client: Presigned URL and file information
Loading

Reviews (1): Last reviewed commit: "fix(files): authorize presigned upload c..." | Re-trigger Greptile

@waleedlatif1
waleedlatif1 merged commit 51dd0df into staging Aug 2, 2026
27 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/presigned-upload-context-authz branch August 2, 2026 00:53
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