Files
sim/apps/sim/lib/a2a
Waleed 6503671102 fix(security): harden findings — path traversal, SSRF, IDOR, file auth, credential access (#4571)
* fix(security): harden HIGH deepsec findings across multiple attack surfaces

- Supabase tools (get_row, delete, update): validate table name with strict
  identifier regex and encodeURIComponent to prevent LLM-controlled path
  traversal to admin endpoints; add missing empty-filter guard to update
  matching the delete.ts pattern

- SFTP/SMTP/SharePoint upload routes: add verifyFileAccess ownership check
  before downloadFileFromStorage, matching the WordPress reference pattern;
  rejects files the requesting user does not own with 404

- Gmail labels, OneDrive folders, Wealthbox items (×2): replace bare
  resolveOAuthAccountId + workspace-only membership check with
  authorizeCredentialUse which enforces credentialMember table; use
  credentialOwnerUserId for token refresh instead of bare accountRow.userId

- A2A utils: thread pre-resolved IP from validateUrlWithDNS into A2A SDK
  via pinnedFetch (secureFetchWithPinnedIP) for JsonRpcTransportFactory,
  RestTransportFactory, and DefaultAgentCardResolver, closing the TOCTOU
  DNS rebinding window

- SSH utils: cap stdout/stderr accumulation at 16 MB with truncation marker
  to prevent OOM from unbounded command output

- Form DELETE route: replace db.delete() with db.update({archivedAt}) for
  true soft delete matching the schema's archivedAt column

- Workflow admin import: fix Array.isArray() guard that silently dropped
  all variables (export format is Record, not Array)

- Multipart upload: apply checkStorageQuota and MAX_WORKSPACE_FILE_SIZE to
  mothership context, closing the quota bypass for workspace-scoped storage

* fix(security): eliminate workspace env lost-update race with atomic JSONB ops

PUT: use `variables || excluded.variables` in onConflictDoUpdate so
concurrent writes merge atomically in the DB instead of last-writer-wins
at the application layer.

DELETE: replace the read-modify-write upsert with a single UPDATE that
removes keys via the JSONB `-` operator, preventing concurrent deletes
from resurrecting previously-removed secrets.

* fix(security): address audit findings from security fix review

- SMTP send: restructure attachment loop from Promise.all to sequential
  for...of so verifyFileAccess denial returns 404 instead of propagating
  as a generic 500 via the SMTP error classifier

- Supabase tools: extend table-name validation and encodeURIComponent to
  the five previously missed tools — insert, upsert, count, query,
  text_search — completing coverage across all nine Supabase tools

- Credential routes: remove unnecessary `request as any` casts in Gmail,
  OneDrive, and Wealthbox routes; authorizeCredentialUse already accepts
  NextRequest directly

- Form soft delete: also set isActive=false alongside archivedAt so that
  any future code paths querying by isActive see a consistent state

- SSH utils: fix exit code fallback from 0 to -1 so an abnormally closed
  connection that supplies no exit code is not reported as success

- Workspace env: capitalize EXCLUDED.variables in the onConflictDoUpdate
  set clause to make the pseudo-table reference unambiguous

* fix(security): address PR review comments and harden deepsec fixes

- fix(env): replace jsonb operators with transaction+FOR UPDATE read-modify-write
  - PUT: uses db.transaction + SELECT FOR UPDATE + JS merge to avoid lost-update race
  - DELETE: same pattern; fixes variable scope bug where current was referenced outside tx
  - removes broken || and - jsonb operators that fail on json-typed column

- fix(ssh): trim truncated output consistently with non-truncated path

- fix(gmail): remove redundant resolveOAuthAccountId call
  - adds credentialType field to CredentialAccessResult
  - authorizeCredentialUse now returns credentialType in all success paths
  - gmail/labels route uses authz.credentialType and authz.resolvedCredentialId directly

- fix(supabase): centralize table identifier validation
  - adds validateDatabaseIdentifier() to input-validation.ts
  - all 8 supabase tools use the shared util instead of inline regex

* fix(workflows): fix VariableType assignment in admin workflow import route

The intermediate Record cast used 'string' for the type field which TypeScript
correctly rejected — WorkflowVariable.type is 'VariableType', not string.
Changed the cast to use VariableType so both branches typecheck correctly.

* fix(a2a): handle Request objects in pinnedFetch URL extraction

* fix(security): extract shared file-access guard; merge workspace/mothership branch

* fix(security): advisory lock for env first-insert race; handle all BodyInit types in pinnedFetch

* chore: remove inline comment from advisory lock

* fix(security): remove stray comment; narrow credentialType to literal union

* fix(security): add credentialId validation to wealthbox oauth route; fix null body override in pinnedFetch

* fix(security): stream A2A response body to unblock SSE; keep text/json/arrayBuffer for non-streaming callers

* fix(security): resolve credentialId guard on OneDrive, use assertToolFileAccess in WordPress, memoize body buffer to prevent silent empty reads, fix ArrayBuffer type cast

* fix(security): handle string[][] HeadersInit format in pinnedFetch

* fix(security): keep abort listener alive during body streaming; clean up in stream end/error/cancel

* chore: remove extraneous inline comment

* fix(security): cleanup abort listener when maxResponseBytes limit is exceeded
2026-05-12 17:40:25 -07:00
..