From c7e4f8f4020612868cd5a3a5340fc1dbbb8fdedf Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Fri, 27 Feb 2026 08:54:06 -0800 Subject: [PATCH] agents: gate before-tool-call with skill context --- src/agents/pi-tools.before-tool-call.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/agents/pi-tools.before-tool-call.ts b/src/agents/pi-tools.before-tool-call.ts index a0a5ca4cb11c..47a419480236 100644 --- a/src/agents/pi-tools.before-tool-call.ts +++ b/src/agents/pi-tools.before-tool-call.ts @@ -2,6 +2,7 @@ import type { ToolLoopDetectionConfig } from "../config/types.tools.js"; import type { SessionState } from "../logging/diagnostic-session-state.js"; import { createSubsystemLogger } from "../logging/subsystem.js"; import { getGlobalHookRunner } from "../plugins/hook-runner-global.js"; +import { checkToolAgainstSkillPolicy } from "../security/skill-security-context.js"; import { isPlainObject } from "../utils.js"; import { normalizeToolName } from "./tool-policy.js"; import type { AnyAgentTool } from "./tools/common.js"; @@ -80,6 +81,20 @@ export async function runBeforeToolCallHook(args: { const toolName = normalizeToolName(args.toolName || "tool"); const params = args.params; + // Skill security enforcement — check before any plugin hooks. + // This is a hard code gate: no prompt injection can bypass it. + const skillPolicyBlock = checkToolAgainstSkillPolicy(toolName); + if (skillPolicyBlock) { + log.warn(`Tool blocked by skill policy: ${toolName}`, { + category: "security", + tool: toolName, + reason: skillPolicyBlock, + agentId: args.ctx?.agentId ?? null, + sessionKey: args.ctx?.sessionKey ?? null, + }); + return { blocked: true, reason: skillPolicyBlock }; + } + if (args.ctx?.sessionKey) { const { getDiagnosticSessionState } = await import("../logging/diagnostic-session-state.js"); const { logToolLoopAction } = await import("../logging/diagnostic.js");