From 9ad88d5ce8c420041c8afac408a137ada8ddddf2 Mon Sep 17 00:00:00 2001 From: Autumn-27 <53844290+Autumn-27@users.noreply.github.com> Date: Thu, 10 Sep 2026 11:30:28 -0400 Subject: [PATCH] =?UTF-8?q?fix(guard):=20=E6=8B=A6=E6=88=AA=E6=96=87?= =?UTF-8?q?=E6=A1=88=E6=A0=87=E6=98=8E=E4=B8=BA=E5=B9=B3=E5=8F=B0=E7=AE=A1?= =?UTF-8?q?=E6=8E=A7=E8=80=8C=E9=9D=9E=E7=9B=AE=E6=A0=87=E9=98=B2=E5=BE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 拦截 deny/ask 回给 agent 的 tool_result 原文案(禁止执行/用户拒绝) 读起来与目标侧 WAF/403 无异,渗透 agent 会当成目标防御去改写命令、 换 payload 尝试绕过。统一经 systemBlockMessage 加平台权威框架,说明 此为平台管控、操作被禁止,引导换方向而非规避。 --- guard/guard.go | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/guard/guard.go b/guard/guard.go index b2d67c4..fd437d9 100644 --- a/guard/guard.go +++ b/guard/guard.go @@ -103,7 +103,7 @@ func (g *Guard) applyIntercept(ctx context.Context, ev hook.Event, cmd string) h case "deny": // 观测:deny 命中不阻塞审批,直接记一条 denied(历史/任务拦截页可见)。 g.interceptor.Log(ctx, intercept.ConvIDFromContext(ctx), dec, ev.ToolName, ev.Input, "denied") - return g.block(ev.ToolName, dec.Message, "") + return g.block(ev.ToolName, systemBlockMessage(dec.Message), "") case "allow": // Record explicit rule and model approvals so review details remain auditable. g.interceptor.Log(ctx, intercept.ConvIDFromContext(ctx), dec, ev.ToolName, ev.Input, "allowed") @@ -113,17 +113,34 @@ func (g *Guard) applyIntercept(ctx context.Context, ev hook.Event, cmd string) h // immediately without creating a pending record — avoids orphaned DB entries // and makes execOne complete fast, reducing the race against drainSynthetic. if ctx.Err() != nil { - return g.block(ev.ToolName, "工作已取消,拦截规则阻止执行", "") + return g.block(ev.ToolName, systemBlockMessage("工作已取消,平台安全管控阻止执行"), "") } convID := intercept.ConvIDFromContext(ctx) if !g.interceptor.HandleAsk(ctx, convID, dec, ev.ToolName, ev.Input) { - return g.block(ev.ToolName, "用户拒绝或审批超时", "") + return g.block(ev.ToolName, systemBlockMessage("人工审批未通过(用户拒绝或审批超时)"), "") } return hook.Result{} } return hook.Result{} } +// systemBlockMessage frames an intercept block as an ARTEX platform-governance +// decision so the agent does not mistake it for a target-side defense. +// +// The bare reasons ("禁止执行此工具" / "用户拒绝") read exactly like a WAF/403 on +// the target, so a pentest agent's instinct is to bypass them — rewrite the +// command, swap the payload, re-encode, retry. That is both futile (the platform +// blocks the class of action, not one string) and wrong (it's a policy decision, +// not an obstacle to defeat). This prefix states plainly that the block comes +// from the platform, is not the target's protection, and that the operation is +// forbidden — so the agent pivots to another approach instead of evading it. +// Audit/history rows keep the raw reason (see Interceptor.Log); only the +// model-facing tool_result carries this framing. +func systemBlockMessage(reason string) string { + return "【ARTEX 平台管控·非目标防御】此调用被平台拦截。" + + "原因:" + reason + "。此操作被禁止。" +} + // judgeSubject builds the text the LLM fallback judge evaluates: the shell // command for shell tools, or the raw tool input JSON for others (Write/Edit/…) // so the model sees what is being written/requested.