-
Notifications
You must be signed in to change notification settings - Fork 9.8k
Description
Description
Plugin hooks using tool.execute.before successfully block tool calls from primary agents but do not intercept tool calls from subagents spawned via the task tool. This allows security policies implemented via plugins to be completely bypassed.
Security Impact
This is a critical security issue for projects using plugins to enforce:
- Code quality guardrails (e.g., enforcing GritQL for all code modifications)
- Access control policies (e.g., blocking certain tools or commands)
- Compliance requirements (e.g., audit logging of all tool executions)
Attack vector: Any agent can bypass plugin restrictions by delegating work to a subagent using thetasktool.
Reproduction Steps
1. Create a plugin that blocks grep and glob tools
.opencode/plugin/test-guardrails.ts:
import type { Plugin } from "@opencode-ai/plugin"
export const TestGuardrails: Plugin = async ({ project }) => {
console.log("[TestGuardrails] Plugin loaded for project:", project.name)
return {
"tool.execute.before": async (input, output) => {
const toolName = (input?.tool ?? '').toLowerCase().trim()
console.log("[TestGuardrails] Tool called:", toolName)
// Block grep and glob
if (toolName === 'grep' || toolName === 'glob') {
throw new Error(`Tool '${toolName}' is BLOCKED by test guardrails`)
}
export default TestGuardrails
2. Test with primary agent (WORKS ✅)
In OpenCode TUI, try to use grep directly
Search for files containing "Plugin"
Result: Tool is blocked with error message Tool 'grep' is BLOCKED by test guardrails
3. Test with subagent (FAILS ❌)
In OpenCode TUI, use task tool to invoke subagent
@general find all files containing the word "Plugin"
Result: Subagent successfully uses grep/glob tools without triggering the plugin hook
Expected Behavior
- Plugin hooks should fire for all tool executions regardless of which agent makes the call
- Subagents spawned via task tool should inherit plugin hooks from the project
- Console should log: [TestGuardrails] Tool called: grep when subagent uses grep
Actual Behavior - Plugin hooks only fire for primary agent tool calls
- Subagents bypass plugin hooks entirely
- No console logs appear when subagent uses blocked tools
- Security policies can be completely circumvented
Environment - OpenCode Version: 1.0.182 (latest as of 2024-12-21)
- OS: macOS (also affects Linux)
- Installation Method: npm/homebrew
- Plugin Location: .opencode/plugin/ (project-level)
Workaround
According to OpenCode documentation (https://opencode.ai/docs/agents#tools), tool restrictions can be configured per-agent in opencode.json
Limitations of workaround:
- Must manually configure every built-in subagent
- Does not work for custom subagents created by users
- Duplicates policy logic (once in plugin, once in agent config)
- Not scalable for complex security policies
Proposed Solution
Option 1: Plugin Hook Propagation (Preferred) - Ensure tool.execute.before hooks fire for subagent tool calls
- Plugins loaded at project level should apply to all agents in that project
- Maintain consistent security boundary across agent hierarchy
Option 2: Documentation Update - If subagent tool isolation is intentional, clearly document this limitation
- Provide guidance on securing subagents via agent-level config
- Add warning about security implications of using task tool with plugins
Related Documentation - Plugins Documentation (https://opencode.ai/docs/plugins)
- Agents Documentation (https://opencode.ai/docs/agents)
- Tools Documentation (https://opencode.ai/docs/tools)
Additional Context
This issue was discovered while implementing a strict GritQL-only code modification policy. The goal was to enforce that all code search/modification must go through GritQL (structural code search) rather than raw grep/sed/edit operations for consistency and safety.
The plugin works perfectly for primary agents but becomes ineffective when agents delegate to subagents, making the entire security layer bypassable.
OpenCode version
1.0.182
Steps to reproduce
1: Create a test plugin that blocks grep/glob tools
Create .opencode/plugin/test-block.ts in your project:
import type { Plugin } from "@opencode-ai/plugin"
export const TestBlock: Plugin = async () => {
return {
"tool.execute.before": async (input) => {
const tool = input?.tool?.toLowerCase()
if (tool === 'grep' || tool === 'glob') {
throw new Error(`BLOCKED: ${tool} tool is not allowed`)
}
}
}
}
export default TestBlock
2: Verify plugin blocks primary agent (expected to work)
- Start OpenCode in your project: opencode
- In the TUI, ask: "Search for all TypeScript files"
- Expected result: Error message appears: BLOCKED: glob tool is not allowed
- Observation: ✅ Plugin successfully blocks the primary agent
3: Test if plugin blocks subagent
- Still in OpenCode TUI, ask: "@general find all files containing the word Plugin"
- Expected result: Should show same error: BLOCKED: grep tool is not allowed
- Actual result: ❌ Subagent successfully searches and returns results
- Observation: Plugin hook did NOT fire - security policy was bypassed
Screenshot and/or share link
No response
Operating System
No response
Terminal
Ghostty