You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(inbox): stop an unattributed sender inheriting owner write authority (#7006)
* fix(inbox): stop an unattributed sender inheriting owner write authority
resolveInboxExecutionActor refuses to name a raw-secret actor when the sender
matches no workspace member, then hands the run ws.ownerId for everything else.
That identity also supplies userPermission, which is what executeTool gates on,
so the owner's admin satisfied every requiredPermission check.
In headless mode the client-routed workflow tools fall back to their registered
server handlers (see the comment in tool-executor/executor.ts), so create_workflow,
edit_workflow and run_workflow — all requiredPermission 'write' — were reachable.
runWorkflowFromCopilot then executes with enforceCredentialAccess and the owner as
actor, which resolves the owner's workspace and personal secrets. An allowlisted
external correspondent could therefore reach, through a workflow it had the agent
build and run, exactly what the null secret actor refuses for a direct mount.
Cap the run's tool permission at read when no member owns the message. An
attributed message is unchanged and still uses the sender's own permission, so a
read-only member emailing the inbox still cannot run or edit anything. Read rather
than none because answering an external correspondent from workspace context is
the point of the inbox; only mutation and execution are withheld.
The owner identity itself stays: billing attribution and workspace reads need a
real user. This separates that need from the authority that came with it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(copilot): bar the headless client-tool fallback below write
Client-routed tools carry no catalog requiredPermission because the browser runs
them through the workflow APIs, which authorize the caller's own session. The
headless fallback in executeTool has no session and runs under the request's
principal instead, with nothing standing in for that check.
So the read cap from the previous commit did not reach run_workflow,
run_workflow_until_block, run_block or run_from_block: all four are route
'client' with no requiredPermission, unlike create_workflow and edit_workflow.
An unattributed inbox sender could therefore still run an existing workflow,
which executes with enforceCredentialAccess under the workspace owner and
resolves the owner's workspace and personal secrets.
Derive the requirement at the gate instead: a client-routed tool taking the
headless fallback requires write. Interactive callers never reach this branch,
so the browser path is unaffected. The catalog itself is generated from the
copilot contracts repo and cannot carry this rule, which only applies to the
fallback.
Also corrects the inboxToolPermission doc, which claimed run_workflow gates on
requiredPermission 'write'. It does not; it is gated here.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
0 commit comments