想靠 SECURITY_RULES.md 不够:你需要一个 tool:pre 安全闸

想靠 SECURITY_RULES.md 不够:你需要一个 tool:pre 安全闸

OpenClaw 的 GitHub 上刚出了一个 Feature Request(#12311),标题直截了当:给工具执行加一个 tool:pre 生命周期钩子。

提需求的人在生产环境跑着多个 Agent,有些 Agent 只应该有只读权限(比如安全审计 Agent),有些 Agent 可以写文件、执行命令。他现在的做法是在 SECURITY_RULES.md 里写规则,然后"训练" Agent 遵守。

问题是:Agent 不一定听话。

当前的权限控制能做什么

OpenClaw 有一个 tools.deny 配置,可以禁止 Agent 使用某些工具。比如:

{
  "tools": {
    "deny": ["write", "edit", "apply_patch"]
  }
}

这样配置之后,Agent 根本拿不到这些工具,无法调用。这是硬限制,可靠。

tools.deny 是粗粒度的。它只能"整个禁用一个工具",不能"允许用这个工具但限制参数"。

举个例子:你希望 Agent 能用 exec 工具执行 lscatgrep,但不能执行 rmcurlevaltools.deny 做不到这个。要么全禁 exec(Agent 失去执行能力),要么全放(安全风险)。

SECURITY_RULES.md 的局限

目前很多 OpenClaw 用户的做法是写一个 SECURITY_RULES.md,内容类似:

## 安全规则
- 不要执行 rm、rmdir、del 等删除命令
- 不要执行 curl、wget 把数据发送到外部地址
- 不要读取 ~/.ssh/ 目录下的文件
- 不要在命令中使用 eval()

然后把这个文件放到 Agent 的上下文里,期望 Agent 自觉遵守。

但这依赖 LLM 的"合规性"。正常情况下模型会遵守,但 prompt injection 可以绕过。Cisco 的安全团队已经演示过:一个恶意的 OpenClaw 技能(skill)可以在 prompt 里注入指令,强制 Agent 忽略安全规则并执行数据窃取命令。Agent 不是不想守规矩,是有人改了它的"想法"。

说白了:advisory 规则管不住被注入的 Agent。

tool:pre 钩子是什么

#12311 提议的方案是在工具执行前加一个程序化的拦截点。配置方式:

{
  "hooks": {
    "internal": {
      "entries": {
        "security-gate": {
          "on": ["tool:pre"],
          "script": "./hooks/security-gate.js"
        }
      }
    }
  }
}

当 Agent 准备调用某个工具时,先跑 security-gate.js。这个脚本拿到工具名称、参数、会话信息,返回三种结果之一:

  • allow:放行
  • block:拦截,返回原因
  • modify:修改参数后放行

一个检测危险命令的示例:

export default function({ tool, params }) {
  const DANGEROUS = [/\beval\s*\(/i, /child_process/, /os\.system/];
  
  if (tool === "exec" && params.command) {
    for (const pattern of DANGEROUS) {
      if (pattern.test(params.command)) {
        return { action: "block", reason: `命令匹配危险模式: ${pattern}` };
      }
    }
  }
  return { action: "allow" };
}

这是程序化的、确定性的。不管 Agent 被注入了什么,不管它"想"执行什么,只要命令匹配危险模式,就拦住。

这跟 exec approvals 有什么区别

OpenClaw 已有一个 exec approvals 机制:Agent 要执行命令时,先发一条审批请求到你的 Telegram/Discord,等你点"approve"之后才执行。

exec approvals 是人工审批,适合高风险操作。但它有两个问题:

一,延迟。审批需要人工介入,可能等几分钟甚至更久。如果 Agent 每天执行几百条命令,你不可能每条都审。

二,审批疲劳。审多了就开始无脑点 approve,跟弹窗警告点"确定"一样。安全性名存实亡。

tool:pre 钩子是自动化的。它在毫秒级完成判断,不需要人工介入。高频、低延迟的安全检查,人做不了,但代码可以。

两者不互斥。合理的组合是:tool:pre 做自动化过滤(拦截明确的危险模式),exec approvals 做兜底(对 tool:pre 放行但仍然敏感的操作要求人工确认)。

实际的安全场景

几个 tool:pre 可以直接解决的场景:

凭据泄露拦截。Agent 可能无意中在 exec 命令里暴露环境变量:echo $OPENAI_API_KEYtool:pre 可以扫描命令参数里的环境变量引用,拦截或脱敏。

SSRF 防护。Agent 使用 web_search 或 fetch 工具时,URL 可能指向内网地址(127.0.0.110.x.x.x)。tool:pre 可以验证 URL 不指向私有网段。

路径穿越防护。Agent 读写文件时,路径可能包含 ../,逃出预期的工作目录。tool:pre 可以规范化路径并检查是否在允许的范围内。

速率限制。某些工具调用代价高昂。tool:pre 可以按会话、按 Agent 做计数,超过阈值就拒绝。

在 tool:pre 落地之前怎么办

#12311 还没被合并。如果你现在就需要类似能力,有几个临时方案。

用 exec 的 allowlist 做白名单。OpenClaw 的 exec 工具支持 safeBins 配置,只允许执行指定的命令。这是命令级别的白名单,比 tools.deny 细一级。

{
  "tools": {
    "exec": {
      "security": "allowlist",
      "safeBins": ["ls", "cat", "grep", "git", "node"]
    }
  }
}

用已有的 before_tool_call plugin hook。2026.2.1 的 CHANGELOG 里提到"wire before_tool_call plugin hook into tool execution"。这个 hook 已经在代码里了,但文档没有详细说明。你可以写一个 plugin,在 before_tool_call 事件里做参数检查。

给不同 Agent 分配不同权限。安全审计 Agent 配置 tools.deny 禁掉写入类工具。执行类 Agent 只开放需要的工具。这是最笨但最可靠的方式。

更远的方向

Claude Code 已经有一个类似的机制叫 PreToolUse。模型执行工具前会先过一个权限检查。但 Claude Code 的实现是跟模型绑定的,你用 Anthropic 的模型才有这个能力。

OpenClaw 作为模型无关的 Agent 框架,需要在框架层面自己做这件事。tool:pre 如果落地了,意味着不管你用什么模型——Claude、GPT、Grok、本地 Ollama——安全策略都统一由框架执行,不依赖模型的"自觉"。

这才是正路。安全策略不应该是"请求模型遵守",而应该是"代码强制执行"。


参考链接

  • OpenClaw Feature Request #12311:https://github.com/openclaw/openclaw/issues/12311
  • Cisco 恶意技能演示:https://blogs.cisco.com/ai/personal-ai-agents-like-openclaw-are-a-security-nightmare
  • OpenClaw Exec Approvals 文档:https://docs.clawd.bot/tools/exec-approvals
← 返回博客列表