Skip to content

code mode: execute dispatcher bypasses ask permission for nested plugin tools #47177

Closed as duplicate

Description

@CyberNekokoya

Summary

In a Code Mode session, plugin tools invoked through the execute dispatcher do not surface the configured ask permission. A mutation tool declared with options.permission mapped to an ask rule executes silently, with no permission prompt in the client.

Environment

  • opencode version: 0.0.0-beta-18999 (opencode2, beta channel)
  • OS: Linux Cyber-Nekokoya 7.2.2-zen1-1-zen x86_64 (Arch)
  • Terminal: TERM=xterm-256color, COLORTERM=truecolor
  • Shell: /usr/bin/zsh
  • Install/channel: beta (local @opencode-ai/cli)
  • Active plugins:
    • server (auto-discovered local): session-tools.ts, systemd-user-tools.ts
    • cli.json TUI plugins: ./plugins/sandbox-toggle, ./plugins/git-write-toggle

Reproduction

  1. Global opencode.jsonc has rules such as { "action": "systemd_user_start", "resource": "*", "effect": "ask" }.
  2. A server plugin exposes a tool with options: { permission: "systemd_user_start" } via context.tool.transform((e) => e.add(...)).
  3. In a Code Mode session, invoke that tool through the dispatcher, e.g. an execute block calling tools["systemd_user_start"]({ unit: "wivrn.service" }).
  4. Observe: the unit starts/stops successfully, and the client never shows an ask prompt (no permission.asked event; compare with early-session direct tool calls, which did produce asking id=per_... log lines).

Expected Behavior

The docs for the execute action state each nested tool still enforces its own permission. An ask rule should prompt the user (or be rejected when no interactive channel is available).

Actual Behavior

The ask rule is bypassed: mutation tools execute silently through the execute dispatcher. In our session systemd_user_start/stop for wivrn.service ran with no confirmation. Risk: any ask-class plugin tool is unenforced in Code Mode.

Additional Context

  • Reproducible consistently via execute.
  • Direct (non-dispatcher) tool calls in the same environment do prompt, so the bypass appears specific to the Code Mode dispatcher path.
  • No saved "allow always" approval exists for these actions; config rules are intact ask.

Activity

  1. github-actions commented on Sep 4, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of or closely related to existing issues. Please check:

  2. CyberNekokoya commented on Sep 4, 2026

    @CyberNekokoya
    Author

    Update: this is broader than the Code Mode dispatcher path. Local server plugin tools bypass the permissions engine entirely — not just the ask prompt, but deny rules too.

    Additional evidence (native tool path, not execute)

    With a local server plugin exposing tools that declare options.permission/codemode: false, and global permissions in opencode.jsonc:

    1. systemd_user_start with rule { action: "systemd_user_start", resource: "*", effect: "ask" } → executes silently, no permission.asked event (client polling GET /api/session/<id>/permission returns 404 the whole time).
    2. Same tool with the rule changed to effect: "deny" → still executes successfully.
    3. A read-only plugin tool with its rule changed to effect: "deny" → also still executes (confirms the engine is not being consulted at all for plugin tools).
    4. Control: a built-in tool (writing a file outside the workspace, edit + external_directory = ask) → prompts correctly in the same client/session.

    Conclusion

    Plugin-registered tools are invoked without permission evaluation regardless of execute vs native listing, and regardless of codemode. ask, deny, and allow rules have no effect on them. Built-in tools are unaffected. This makes permission enforcement for plugin tools unreliable end-to-end.

  3. neriousy commented on Oct 20, 2026

    @neriousy
    Member

    Thanks for the report and for checking that both ask and deny rules are bypassed on direct plugin calls too. This is the same problem as #50652, where we're tracking plugin-tool permission enforcement; please subscribe there or add your deny-rule findings, which are useful extra details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions