Skip to content

Commit 1adf95c

Browse files
NamedIdentityclaude
andcommitted
fix(task): enforce permission checks for subagent-to-subagent delegation
Fixes a critical bug where bypassAgentCheck flag (set when user invokes agents with @ or when prompt resolution creates agent parts) was propagating to Task tool calls made BY subagents, causing permission rules to be ignored. Root cause: - When Task tool creates a subagent session, resolvePromptParts() may create "agent" type parts if prompt contains unresolved {file:...} references - This triggers bypassAgentCheck=true for the entire subagent session - All subsequent Task calls by that subagent bypass permission checks Fix: - Move isSubagent check before permission check - Always enforce permissions when caller is a subagent, even if bypassAgentCheck is set - Preserves OpenCode's intended behavior: user @ invocation can bypass, but subagent-to-subagent delegation always checks permissions Impact: - Subagent permission.task rules now work correctly - User @ invocation bypass still works (OpenCode behavior preserved) - Fixes reported issue: assistant-sonnet could task any agent despite permission rules denying it Tests: 6/6 passing Typecheck: Clean Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 7e3e5a7 commit 1adf95c

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

packages/opencode/src/tool/task.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,13 @@ export const TaskTool = Tool.define("task", async (ctx) => {
5959
async execute(params: z.infer<typeof parameters>, ctx) {
6060
const config = await Config.get()
6161

62+
// Get caller's session to check if this is a subagent calling
63+
const callerSession = await Session.get(ctx.sessionID)
64+
const isSubagent = callerSession.parentID !== undefined
65+
6266
// Skip permission check when user explicitly invoked via @ or command subtask
63-
if (!ctx.extra?.bypassAgentCheck) {
67+
// BUT: always check permissions for subagent-to-subagent delegation
68+
if (!ctx.extra?.bypassAgentCheck || isSubagent) {
6469
await ctx.ask({
6570
permission: "task",
6671
patterns: [params.subagent_type],
@@ -75,10 +80,6 @@ export const TaskTool = Tool.define("task", async (ctx) => {
7580
const targetAgent = await Agent.get(params.subagent_type)
7681
if (!targetAgent) throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`)
7782

78-
// Get caller's session to check if this is a subagent calling
79-
const callerSession = await Session.get(ctx.sessionID)
80-
const isSubagent = callerSession.parentID !== undefined
81-
8283
// Get caller agent info for budget check (ctx.agent is just the name)
8384
const callerAgentInfo = ctx.agent ? await Agent.get(ctx.agent) : undefined
8485

0 commit comments

Comments
 (0)