Task tool ignores per-target deny and allows self-dispatch recursion #8059

Open
opened 2026-02-16 18:09:02 -05:00 by yindo · 2 comments
Owner

Originally created by @HyunggyuJang on GitHub (Jan 30, 2026).

Originally assigned to: @thdxr on GitHub.

Summary

Task tool ignores per-target deny rules and allows an agent to dispatch itself. This enables recursive subagent spawning (self-dispatch loop) even when permission.task denies that target.

Steps to reproduce

  1. Define an agent sre with task permission allowing * but denying sre as a target.
# opencode.json (agent snippet)
permission:
  task:
    "*": allow
    sre: deny
  1. Start a session as @sre.
  2. Invoke the Task tool with subagent_type: "sre".

Example payload:

{
  "tool": "task",
  "arguments": {
    "subagent_type": "sre",
    "prompt": "...",
    "description": "..."
  }
}

Expected

The Task tool call is rejected with a permission error because the target sre is denied.

Actual

The Task tool call succeeds and spawns @sre again, enabling recursive self-dispatch loops.

Impact

  • Deny rules for specific subagent targets are not enforced at execution time.
  • Self-dispatch loops can create runaway subagent chains.

Workaround

Add a custom guard in tool.execute.before to reject Task calls when the current agent is sre and subagent_type is sre.

Environment

  • Observed on macOS with current anomalyco/opencode main (date: 2026-01-31)
  • Configured via agent permissions (see snippet above)
Originally created by @HyunggyuJang on GitHub (Jan 30, 2026). Originally assigned to: @thdxr on GitHub. ## Summary Task tool ignores per-target deny rules and allows an agent to dispatch itself. This enables recursive subagent spawning (self-dispatch loop) even when `permission.task` denies that target. ## Steps to reproduce 1. Define an agent `sre` with task permission allowing `*` but denying `sre` as a target. ```yaml # opencode.json (agent snippet) permission: task: "*": allow sre: deny ``` 2. Start a session as `@sre`. 3. Invoke the Task tool with `subagent_type: "sre"`. Example payload: ```json { "tool": "task", "arguments": { "subagent_type": "sre", "prompt": "...", "description": "..." } } ``` ## Expected The Task tool call is rejected with a permission error because the target `sre` is denied. ## Actual The Task tool call succeeds and spawns `@sre` again, enabling recursive self-dispatch loops. ## Impact - Deny rules for specific subagent targets are not enforced at execution time. - Self-dispatch loops can create runaway subagent chains. ## Workaround Add a custom guard in `tool.execute.before` to reject Task calls when the current agent is `sre` and `subagent_type` is `sre`. ## Environment - Observed on macOS with current `anomalyco/opencode` main (date: 2026-01-31) - Configured via agent permissions (see snippet above)
Author
Owner

@github-actions[bot] commented on GitHub (Jan 30, 2026):

This issue might be a duplicate of existing issues. Please check:

  • #7474: [Security Bug] Subagent permissions not enforced - configured restrictions ignored
  • #6527: [Security Issue/Bug] Plan mode restrictions bypassed when spawning sub-agents
  • #5894: [BUG] Plugin hooks (tool.execute.before) don't intercept subagent tool calls - security policy bypass
  • #3808: Task should inherit current agent permissions/tools for MCP
  • #7296: [FEATURE]: Allow configurable subagent-to-subagent task delegation with call limits

The core issue appears to be that the task tool systematically ignores configured permission rules. The most relevant are #7474 (nearly identical - ignoring per-target permissions) and #6527 (same root cause - restrictions ignored).

Feel free to ignore if your specific case isn't addressed by these issues.

@github-actions[bot] commented on GitHub (Jan 30, 2026): This issue might be a duplicate of existing issues. Please check: - #7474: [Security Bug] Subagent permissions not enforced - configured restrictions ignored - #6527: [Security Issue/Bug] Plan mode restrictions bypassed when spawning sub-agents - #5894: [BUG] Plugin hooks (tool.execute.before) don't intercept subagent tool calls - security policy bypass - #3808: Task should inherit current agent permissions/tools for MCP - #7296: [FEATURE]: Allow configurable subagent-to-subagent task delegation with call limits The core issue appears to be that the task tool systematically ignores configured permission rules. The most relevant are #7474 (nearly identical - ignoring per-target permissions) and #6527 (same root cause - restrictions ignored). Feel free to ignore if your specific case isn't addressed by these issues.
Author
Owner

@HyunggyuJang commented on GitHub (Jan 30, 2026):

I inspected packages/opencode/src/tool/task.ts (lines ~23-60). Root cause: per-target deny is only used to filter the tool description (accessibleAgents). The execute path does not enforce it and proceeds to Agent.get even when PermissionNext.evaluate("task", params.subagent_type, caller.permission) is deny.

Suggestion (treat deny as not existing): add a guard in execute before Agent.get:

if (ctx.agent && PermissionNext.evaluate("task", params.subagent_type, ctx.agent.permission).action === "deny") {
  throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`)
}

This keeps denied targets hidden and prevents self-dispatch loops (e.g., @sre -> task(subagent_type: "sre")).

@HyunggyuJang commented on GitHub (Jan 30, 2026): I inspected `packages/opencode/src/tool/task.ts` (lines ~23-60). Root cause: per-target deny is only used to filter the tool description (accessibleAgents). The execute path does not enforce it and proceeds to `Agent.get` even when `PermissionNext.evaluate("task", params.subagent_type, caller.permission)` is `deny`. Suggestion (treat deny as not existing): add a guard in execute before `Agent.get`: ```ts if (ctx.agent && PermissionNext.evaluate("task", params.subagent_type, ctx.agent.permission).action === "deny") { throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`) } ``` This keeps denied targets hidden and prevents self-dispatch loops (e.g., @sre -> task(subagent_type: "sre")).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#8059