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
{{ message }}
Repository navigation
MCP tools: ownership checks and cleanup after the access gate #15962
Follow-ups from the MCP access declarations (#16335, which replaced #15961). I audited all 72 T3 MCP tools; these gaps are outside what the gate checks, because they depend on who owns a resource rather than on the caller's modes.
Ownership checks missing
device_screenshot with an explicit deviceId doesn't check that device belongs to the calling thread's sessions, so a thread can screenshot a device another thread opened (apps/server/src/mcp/toolkits/device/handlers.ts, the deviceId branch).
Preview tab ownership isn't enforced on the server: the broker uses tab ownership only to pick a host and forwards threadId/tabId to the desktop (PreviewAutomationBroker.ts). Confirm the desktop refuses another thread's tab, or check it here.
t3_attachment_discard doesn't check that the pending upload belongs to the caller (toolkits/attachment/handlers.ts).
Annotations that don't match behavior
preview_snapshot is annotated read-only but writes a PNG to disk with save: true.
preview_open declares Destructive: false, but browserTool overwrites it to true.
feat(server): every T3 MCP tool declares who may call it #16335 removed the per-handler copies of the caller checks (readMutationCaller, readFullAccessCaller, readWritableThread, and the copies in ThreadMetadataMcpService and the pull-request handlers). OrchestratorMcpService still repeats some internally: loadCaller, assertLiveCallerForOtherThread/ForOtherProject, and its own mode checks in send, interrupt and scheduled-task updates. These can shrink to the checks only it can make, such as a task belonging to its parent.
OrchestratorMcpService.loadCaller doesn't check whether the calling thread is deleted. The declarations cover this for every call, but the service-level helper is still inconsistent with threadAccess.loadCaller.
Decided
t3_thread_launch with scratch: true stays open to any caller within its own modes, including Supervised (Julius, 2026-10-05).
Follow-ups from the MCP access declarations (#16335, which replaced #15961). I audited all 72 T3 MCP tools; these gaps are outside what the gate checks, because they depend on who owns a resource rather than on the caller's modes.
Ownership checks missing
device_screenshotwith an explicitdeviceIddoesn't check that device belongs to the calling thread's sessions, so a thread can screenshot a device another thread opened (apps/server/src/mcp/toolkits/device/handlers.ts, thedeviceIdbranch).threadId/tabIdto the desktop (PreviewAutomationBroker.ts). Confirm the desktop refuses another thread's tab, or check it here.t3_attachment_discarddoesn't check that the pending upload belongs to the caller (toolkits/attachment/handlers.ts).Annotations that don't match behavior
preview_snapshotis annotated read-only but writes a PNG to disk withsave: true.preview_opendeclaresDestructive: false, butbrowserTooloverwrites it totrue.Cleanup left after #16335
readMutationCaller,readFullAccessCaller,readWritableThread, and the copies inThreadMetadataMcpServiceand the pull-request handlers).OrchestratorMcpServicestill repeats some internally:loadCaller,assertLiveCallerForOtherThread/ForOtherProject, and its own mode checks in send, interrupt and scheduled-task updates. These can shrink to the checks only it can make, such as a task belonging to its parent.OrchestratorMcpService.loadCallerdoesn't check whether the calling thread is deleted. The declarations cover this for every call, but the service-level helper is still inconsistent withthreadAccess.loadCaller.Decided
t3_thread_launchwithscratch: truestays open to any caller within its own modes, including Supervised (Julius, 2026-10-05).