Skip to content

fix(mothership): hold callerless runs' sim_cli to read API scopes - #9371

Merged
waleedlatif1 merged 3 commits into
stagingfrom
fix/sim-cli-permission-cap
Oct 24, 2026
Merged

waleedlatif1 merged 3 commits into
stagingfrom
fix/sim-cli-permission-cap

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • An unattributed inbox message (sender is not a workspace member) runs as the workspace owner with its tool permission capped to read. sim_cli has no catalog requiredPermission, so executeTool never applied the cap, and every CLI command authorized the delegated subject's live role — the owner's. The CLI could create/edit/delete workflows, run workflows, write project files, and set the owner's personal secrets
  • Callerless runs (secretActorUserId: null) now execute the CLI inside a delegated API-scope grant of api:read (withDelegatedApiScopes)
  • requireOAuthOperationScope enforces that grant for delegated principals the same way it enforces an OAuth token's scopes. Every workspace, project-file, file-copy and org authorization path already calls it, so this covers v2 routes and the transports that call use cases directly
  • The line is each operation's declared oauthScope, not HTTP method or minimumRole: v2 has read POSTs (table query, knowledge search, selectors) and write/execute ops at minimumRole: 'read' (workflows.execute, secrets.set, credential/skill ACL changes). Every Copilot-admitted v2 route declares a scope; operations with none are internal and keep their own policy
  • CLI services route into mixed server tools (settings, dashboards, tests, search_sources, workspaces) whose writes run through operations that declare no API scope or authorize outside the operation layer. Each tool now declares which validated arguments write (BaseServerTool.writes), and the router holds those to the delegated grant (requireDelegatedApiScope)
  • Keyed on the recorded no-caller authority rather than userPermission, so in-band (background subagent) calls — which carry no userPermission — are capped too, and read-only members keep exactly their role's reach

Type of Change

  • Bug fix (security)

Testing

  • project-file-read.integration.ts against real Postgres/Redis (bun run test:integration project-file-read), 17/17:
    • callerless run, main-lane and in-band shapes: workflows create, projects files create, secrets set --scope personal refused with api:write; nothing written; workflows list still works; the same commands succeed when attributed
    • read-only member: personal secrets set still succeeds; workflows create refused by role, not by scope
  • callerless settings update of the workspace inbox's secretScope through a CLI service: refused, row unchanged; succeeds when attributed
  • Red proofs: removing the router write check lets the callerless inbox-settings write through; removing the scope install, or the delegated branch in requireOAuthOperationScope, makes the capped writes succeed (vulnerability reproduced); a naive "permission below write" trigger fails the read-member check
  • Targeted vitest (core/application, agent-cli, inbox, mothership tools/router, tool executor, api routes, copilot tools route, auth, project/workspace files): all passing
  • Full type-check / audits / test suite left to CI

Checklist

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

An unattributed inbox message runs as the workspace owner with its tool
permission capped to read, but sim_cli has no catalog permission and its
commands authorize the delegated subject's live role, so the CLI could
create, run, and delete with the owner's authority.

A run with no caller of its own now executes the CLI inside a delegated
API-scope grant of api:read, enforced in requireOAuthOperationScope the
same way an OAuth token's scopes are, so every authorization path the
CLI reaches refuses api:write operations.
@vercel

vercel Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated
docs Skipped Skipped Oct 24, 2026 7:14pm UTC

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/lib/mothership/agent-cli/index.ts Outdated
@greptile-apps

greptile-apps Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new blocking issues were found.

Summary

Caps callerless sim_cli runs to api:read while preserving attributed users’ existing permissions.

  • Callerless CLI runs can read resources but cannot write them.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[sim_cli request] --> B{Callerless run?}
  B -->|Yes| C[Grant api:read]
  B -->|No| D[Keep existing authority]
  C --> E{Request path}
  D --> E
  E -->|Application operation| F[Check declared API scope]
  E -->|Service tool| G[Check writes declaration]
  F --> H[Apply existing access checks]
  G --> H
Loading

Reviews (3) · Last reviewed commit: "test(mothership): model attributed CLI r..." · Reviewed by Greptile

Comment thread apps/sim/lib/core/application/oauth-authorization.ts
…oped CLI writes

Mixed server tools reached through sim_cli services (settings, dashboards,
tests, search_sources, workspaces) write through internal operations that
declare no API scope, so the read grant never bound them. Each tool now
declares which validated arguments write, and the router holds those to
the current delegated grant.

The grant also applies to callerless organization-scoped runs.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

@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 cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 12 files

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Turn on auto-fix | Re-trigger cubic

Comment thread apps/sim/lib/mothership/agent-cli/project-file-read.integration.ts Outdated
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 24, 2026

Copy link
Copy Markdown
Contributor

@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 cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 12 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.

Turn on auto-fix | Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 27f0a83 into staging Oct 24, 2026
68 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/sim-cli-permission-cap branch October 26, 2026 22:30

This branch was previously deployed

1 inactive deployment
Preview — d05552d4 Deployed Oct 24, 2026 by vercel[bot]
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