fix(guard): 拦截文案标明为平台管控而非目标防御
拦截 deny/ask 回给 agent 的 tool_result 原文案(禁止执行/用户拒绝) 读起来与目标侧 WAF/403 无异,渗透 agent 会当成目标防御去改写命令、 换 payload 尝试绕过。统一经 systemBlockMessage 加平台权威框架,说明 此为平台管控、操作被禁止,引导换方向而非规避。
This commit is contained in:
1 parent
01760aa345
commit
9ad88d5ce8
1 file changed
+20
-3
+20
-3
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user