Skip to content

Security Model

jkrandom edited this page Aug 12, 2026 · 1 revision

Security Model

⚠️ Read this before enabling peerPermissions: "allow" on a shared machine.

Trust boundary

Same-machine, same-user trust: any process running as your user can read the registry files and therefore talk to your instances' inboxes. The bearer token protects against other users and accidental connections, not against a malicious process with your UID. This matches the trust level of Claude Code's local IPC.

Prompt injection

A peer message is untrusted input to the model, exactly like text pasted by a user. Plain text cannot transfer:

  • Files or attachments
  • Conversation history
  • Consent or authorization
  • Executable slash commands

Permission auto-approval (peerPermissions: "allow")

With the default peerPermissions: "allow", ordinary tool requests raised during peer-triggered turns are auto-approved. This enables unattended operation but requires trust.

How auto-allow stays scoped

  1. Plugin listens for permission.asked / permission.v2.asked bus events
  2. Walks from the event's tool.messageID (v2: source.messageID) up the parentID chain
  3. If the walk reaches an injected user message (parts carry metadata.peerMessage: true), the turn is peer-triggered
  4. Auto-replies "once" (allow) or "reject" (deny) per the peerPermissions option
  5. Permission requests from your own typed turns get no reply → fall through to opencode's normal prompt flow

Protected-category guardrail (best-effort)

Even in allow mode, the plugin withholds auto-approval for requests that mention:

  • Permission configuration files
  • AGENTS.md
  • Credentials/secrets files (.env, .npmrc, .netrc, .kube, .docker)
  • Shell startup files (.bashrc, .zshrc, .gitconfig)
  • macOS LaunchAgents, crontab

This is a best-effort text match, not a security boundary. A cleverly phrased request can avoid naming those paths (e.g. npm config set x y writes ~/.npmrc without showing the path).

Existing deny rules always win

OpenCode's native deny rules, plugin permission configuration, and AGENTS.md restrictions are evaluated by OpenCode itself and always take precedence over the plugin's auto-approval.

Permission modes

Mode Behavior Use case
"allow" (default) Auto-approve ordinary requests; withhold protected categories Trusted solo workstation
"ask" Leave native prompts untouched for peer turns Collaborative but cautious
"deny" Reject all peer-triggered permission requests Lockdown / CI

Inbound gating

Policy Behavior
"accept" (default) Deliver immediately
"auto" Accept same-directory peers; hold cross-directory
"hold" Park in /peers-inbox for manual review
"refuse" Reject all inbound messages

Recommendations

  • Solo workstation: defaults (accept + allow) are fine
  • Shared workstation: use hold or auto for inbound; use ask for permissions
  • Sensitive codebase: use hold for inbound; use ask or deny for permissions
  • CI/CD: use refuse + deny to effectively disable peer messaging

Loop protection

Messages carry a via hop list. Chains longer than 4 hops are rejected, preventing infinite relay loops between cooperative sessions.

Clone this wiki locally