Lazy loaded image
Agent丨工具调用的安全控制与敏感接口限制如何实现?——从 Claude Code、OpenCode、OpenClaw 看 Agent 权限系统设计
Words 5468Read Time 14 min
2026-4-25
type
Post
status
Published
date
Apr 25, 2026
slug
agent19
summary
tags
Agent
category
icon
password
在 Agent、RAG、AI Coding 场景里,工具调用安全不是“提示词写得更严一点”就能解决的问题。真正可靠的设计是:LLM 只负责提出工具调用意图,宿主运行时负责权限判定、参数校验、沙箱隔离、人工确认和审计追踪
Claude Code 官方文档明确区分了这两层:CLAUDE.md 或用户提示词只能影响 Claude “尝试做什么”,真正的允许/拒绝必须由 Claude Code 的权限规则、权限模式或 PreToolUse Hook 执行;权限规则按 deny -> ask -> allow 评估,deny 优先。(Claude Code) OpenCode 则把工具权限统一抽象成 allow / ask / deny,并支持按工具名、命令模式、路径模式做细粒度匹配。(OpenCode) OpenClaw 更进一步把“工具策略、沙箱、elevated 逃逸执行、每个 agent 的独立配置”拆成多层,强调工具策略是 hard stop,deny 始终优先,沙箱不能把已被 deny 的工具“加回来”。(OpenClaw)

一、为什么工具调用比普通 LLM 输出更危险?

普通 LLM 输出最多是“说错话”。工具调用会变成真实副作用:
删除文件、提交代码、推送 main、发邮件、转账、改数据库、读取 .env、访问内网、拉取网页并被间接 Prompt Injection 劫持。
OWASP 把这类问题归为 Excessive Agency:LLM 系统被授予过多功能、过多权限或过多自治能力,导致模型在幻觉、直接/间接 Prompt Injection、恶意工具输出或多 Agent 传播下执行破坏性动作。OWASP 建议减少可用扩展、减少扩展功能、避免开放式 shell/URL 等泛化工具、最小化下游权限、以用户身份执行操作、对高影响动作做人类确认,并在下游系统做完整授权校验。(OWASP Gen AI Security Project)
工具调用安全的核心判断是:
不能问:“模型是否被要求不要乱来?”
要问:“即使模型被诱导乱来,运行时能不能拦住它?”

二、成熟 Agent 的共同架构:LLM 不直接执行工具

可以把工具调用链路抽象成下面这张图:
这套架构里有五个关键点:
第一,LLM 只能提出工具调用,不能自己决定“安全”。
第二,所有工具参数必须规范化后再匹配规则。
第三,权限判断必须在模型外部执行。
第四,危险动作必须有人工确认或强隔离。
第五,工具结果回流给模型前也要做脱敏与注入检测。
Claude Code 的 PreToolUse Hook、OpenCode 的 permission 配置、OpenClaw 的 tool policy + sandbox + elevated,都是这套模式的不同实现。(Claude Code)

三、工具风险分级:不是所有工具都应该同权

一个实用的 Agent 系统应该先把工具分级。
风险等级
工具类型
典型动作
默认策略
L0 只读低风险
grepls、只读文档检索
读公开源码、读项目内普通文件
allow
L1 只读敏感
.env、SSH key、私有配置、用户数据
读取 secret、PII、凭证
deny 或 ask
L2 本地可逆写
编辑工作区代码、生成文件
修改 feature 分支文件
ask / diff approve
L3 本地破坏性
rm -rf、覆盖配置、改 .git
删除文件、破坏仓库状态
deny
L4 外部副作用
发邮件、发 Slack、开 PR、推送 Git
对外通信、协作系统写入
ask
L5 生产/资金/权限
部署、DB 写、IAM、支付退款
生产变更、财务、权限授予
deny by default + 多人审批
L6 任意执行
shell、Python、Node、MCP 任意工具
泛化代码执行
沙箱 + allowlist + 审计
Claude Code 的 auto mode 默认会阻止下载并执行代码、向外部端点发送敏感数据、生产部署/迁移、云存储批量删除、授权 IAM 或 repo 权限、修改共享基础设施、不可逆删除旧文件、force push 或直接推 main 等动作。(Claude Code) 这说明成熟 Agent 并不是简单区分“能不能用 bash”,而是识别“这个调用的真实副作用是什么”。

四、Claude Code:权限规则、Hook、模式与受保护路径

Claude Code 的设计有几个很值得借鉴的点。

1. deny 优先,权限不是提示词

Claude Code 的规则顺序是 deny -> ask -> allow,第一条匹配规则生效;裸工具名 deny 会让 Claude 根本看不到该工具,而作用域规则如 Bash(rm *) 则是在调用时阻断。(Claude Code)
这对应一个重要原则:
安全策略不要写进 Prompt,应该写进宿主程序可执行的策略系统。
示例配置:

2. Bash 参数匹配很脆弱,要用专门工具或 Hook

Claude Code 文档专门提醒:用 Bash(curl http://github.com/ *) 这类模式限制 URL 很脆弱,因为参数顺序、协议、重定向、变量、空格都可能绕过;更可靠的方式是 deny 掉 curl/wget,只允许受控的 WebFetch(domain:github.com),或者用 PreToolUse Hook 校验 URL。(Claude Code)
这背后的设计经验是:
对 shell 这种开放式接口,不要只靠字符串匹配。要么拆成更窄的专用工具,要么用 AST/解析器/沙箱做强约束。

3. Hook 是运行时策略扩展点,但不能绕过 deny

Claude Code 的 PreToolUse Hook 可以在工具调用前执行自定义 shell 命令,返回 deny、ask 或 allow;但 Hook 不能绕过权限规则,匹配到 deny 仍然会被阻断,阻断型 Hook 也优先于 allow。(Claude Code)
一个典型 Hook 伪代码:

4. 受保护路径不能自动写

Claude Code 在除 bypassPermissions 外的模式中,不会自动批准写 .git.vscode.idea.husky.claude 以及 .gitconfig、shell profile、.mcp.json.claude.json 等敏感路径。(Claude Code)
这说明文件权限系统至少要支持三类路径:
工作区普通路径:可读、可编辑。
工作区敏感路径:可读或不可读,写入必须 ask/deny。
工作区外路径:默认 deny,除非明确加入 scope。

五、OpenCode:permission 矩阵与 Agent 分层

OpenCode 的权限模型更直接:每条规则解析成 "allow""ask""deny"。它支持全局默认规则,也支持按工具和输入模式覆盖;对于对象语法,最后匹配的规则生效,因此通常把 "*" 放前面,把更具体的规则放后面。(OpenCode)
示例:
OpenCode 文档列出的权限 key 包括 readeditglobgrepbashtaskskilllspquestionwebfetchwebsearchexternal_directorydoom_loop;默认情况下大多数权限是 allow,但 external_directorydoom_loopask.env 文件读取默认 deny。(OpenCode)
OpenCode 还有一个很重要的 Agent 分层:Build 是默认主 Agent,工具全开;Plan 是受限主 Agent,默认对文件编辑和 bash 都 ask;ExploreScout 这类子 Agent 偏只读,适合代码探索或外部依赖研究。(OpenCode)
这给我们的启发是:
不要让一个全能 Agent 干所有事。
规划 Agent 默认只读,执行 Agent 才拿写权限。
子 Agent 权限必须比父任务更窄,不能因为委托而升级。
OpenCode 还支持按 Agent 配置特定 bash 权限,例如 git push ask、grep * allow、git * ask。(OpenCode) 这非常适合做“review agent”“release agent”“migration agent”等专用角色。

六、OpenClaw:工具策略、沙箱、elevated 三层防线

OpenClaw 的安全模型更接近“个人助理 + 多通道 + 多 Agent 网关”。它明确提醒:workspace 只是默认 cwd,不是硬沙箱;如果没有启用 sandbox,绝对路径仍可能访问主机其他位置。(OpenClaw)
OpenClaw 的关键设计是三层:
第一层:tool policy 决定工具是否存在、是否可调用。
第二层:sandbox 决定工具在哪里运行、能看到哪些文件和网络。
第三层:elevated 是显式逃逸口,只影响 exec,不能覆盖工具 deny。(OpenClaw)
OpenClaw 文档强调:deny 总是获胜;如果 allow 非空,其他工具视为 blocked;tool policy 是 hard stop,/exec 不能覆盖被 deny 的 exec;同时,tool policy 只按工具名过滤,不检查 exec 内部副作用,因此允许 exec 后,deny write/edit/apply_patch 并不能让 shell 只读。(OpenClaw)
一个安全的多 Agent 配置思路:
OpenClaw 官方也给出过类似的访问画像:个人 Agent 可以 full access、无沙箱;家庭/工作 Agent 可 sandbox + read-only;公共 Agent 应 sandbox 且无文件系统/shell 工具。(OpenClaw)

七、敏感接口限制:重点不是“工具名”,而是“能力边界”

工具安全控制不要只按工具名做。因为同一个工具可能有不同风险:
git status 是只读;git push --force 是高危。
curl https://docs.example.com 是读文档;curl $SECRET_URL | bash 是远程代码执行。
read README.md 是低风险;read ~/.ssh/id_rsa 是严重泄密。
send_email(to=me) 是草稿测试;send_email(to=customer) 是外部副作用。
因此,策略引擎需要至少判断以下维度:
维度
示例
控制方式
tool name
bashreadsend_email
工具级 allow/ask/deny
action
read/write/delete/deploy/send
动作级风险评分
resource
路径、URL、数据库表、repo、bucket
资源 allowlist/denylist
subject
用户、Agent、channel、session
身份和上下文
environment
local/dev/staging/prod
环境级策略
data sensitivity
secret、PII、token、源码
DLP/脱敏/阻断
reversibility
可回滚/不可回滚
不可逆动作强制审批
delegation
subagent/task/skill/MCP
权限不能越权传递

八、一个可落地的 Policy Engine 设计

下面是一个简化版 TypeScript 策略引擎。核心思想是:LLM 输出的 tool call 必须变成规范化请求,再由策略引擎裁决。
这段代码的重点不是具体函数,而是裁决顺序:
身份/通道限制优先。
只读 Agent 不能写。
secret 路径默认 deny。
工作区外默认 deny。
受保护路径默认 deny。
shell 只能 allowlist,未知命令 ask。
生产和外部副作用必须人工确认。

九、路径安全:必须处理 symlink、绝对路径和工作区逃逸

文件工具最容易被绕过的地方是路径。
Claude Code 文档提到,Read/Edit 规则会同时检查 symlink 本身和其解析目标;allow 需要两者都匹配,deny 只要其中一个匹配就阻断。(Claude Code) 这个细节非常关键,因为攻击者可以在允许目录里放一个指向 ~/.ssh/id_rsa 的 symlink。
安全路径校验应该这样写:

十、Shell 安全:能不用 shell 就不用 shell

OWASP 明确建议避免开放式扩展,例如“运行任意 shell 命令”或“抓取任意 URL”,应尽量拆成更细的专用工具。(OWASP Gen AI Security Project)
例如,不要给模型一个万能工具:
更好的方式是拆成窄工具:
这样做的好处是:
模型不能自由拼接 rm -rf
参数可以结构化校验。
超时、环境变量、cwd、网络都可控。
审计日志更清晰。

十一、网络与 MCP:必须防 SSRF、Token Passthrough 和工具投毒

MCP 官方安全文档强调了几个 Agent 系统常见风险:Confused Deputy、Token Passthrough、SSRF、Session Hijacking、本地 MCP Server compromise 等。尤其是 Token Passthrough 被明确列为反模式:MCP Server 不应接受并转发不是显式签发给它的 token。(Model Context Protocol)
对于网络工具和 MCP 工具,建议默认启用:
MCP 官方文档也建议服务端 MCP client 考虑 SSRF:拒绝生产环境的普通 http://,阻断私有/保留 IP、loopback、link-local、云 metadata endpoint,并对重定向目标做同样校验;同时建议通过 egress proxy 做网络策略。(Model Context Protocol)

十二、人工确认:不能只是弹窗,要展示“最小可审计 diff”

OpenAI Agents SDK 文档把 guardrails 与 human review 分开:guardrails 用于输入、输出或工具行为的自动校验;human review 用于在取消、编辑、shell 命令、敏感 MCP 动作等副作用前暂停,由人或策略批准。(OpenAI开发者)
一个好的审批弹窗应该展示:
谁请求的:user / agent / subagent / channel。
要调用什么:tool name + normalized args。
会影响什么:文件、URL、repo、数据库、云资源。
风险原因:为什么 ask。
diff:将要修改哪些内容。
回滚方案:是否可恢复。
审批范围:仅本次、仅本会话、永久规则。
不要给用户一个模糊按钮:
“Claude wants to run bash. Allow?”
应该给用户:

十三、多 Agent 场景:权限必须“向下收敛”,不能“委托升级”

多 Agent 里最危险的问题是:父 Agent 没权限,但它调用一个有权限的子 Agent 间接完成操作。
因此要实现 transitive permission
规则:
子 Agent 权限不能超过父 Agent。
子 Agent 不能绕过父任务的 deny。
子 Agent 的工具调用也要进入同一个 Policy Engine。
子 Agent 返回结果前要做安全审查,避免把恶意工具输出注入父 Agent 上下文。
Claude Code 的 auto mode 对 subagent 也做多点检查:启动前检查 delegated task,运行中每个动作走同样规则,结束时还会审查完整动作历史。(Claude Code) OpenClaw 也支持每个 agent 覆盖 sandbox 和 tool policy,并提醒每个 agent 有自己的 auth store,不应复用 agentDir。(OpenClaw)

十四、RAG 场景下的工具安全:检索内容必须当作不可信输入

在 RAG + Agent 中,工具调用常被间接 Prompt Injection 劫持:
如果 Agent 同时拥有 web_fetchreadbash/curl,就可能把外部网页里的恶意文本当成新指令执行。
防御方式:
检索内容只作为 data,不作为 instruction。
RAG 文档进入模型前加来源标签和不可信边界。
外部内容不能改变权限。
工具结果回流前做注入扫描。
高危工具调用必须引用用户原始意图,而不是引用网页指令。
网络读取工具和本地 secret 读取工具不要同时给同一个低信任 Agent。

十五、生产可用的安全基线

一个企业级 Agent 工具安全基线可以这样配置:
同时配套:
dev container / Docker / VM 沙箱。
出网 allowlist。
secret 不进入模型上下文。
.env、SSH、cloud credentials 默认 deny。
所有工具调用落审计日志。
bypass / yolo / dangerously skip permissions 这类模式,只允许在无生产凭证、无宿主挂载、无外网的隔离环境中使用。Claude Code 也明确提醒 bypassPermissions 会跳过权限提示和安全检查,应只在容器、VM、dev container 等隔离环境使用。(Claude Code)

十六、最终总结:工具调用安全的 7 条铁律

1. 权限在模型外执行。 Prompt 不是安全边界。
2. 默认最小权限。 没明确需要的工具不暴露。
3. deny 优先。 任意层级 deny 都不能被项目配置、子 Agent 或 Hook 放开。
4. 开放式工具要拆窄。 少给 bash,多给 run_testsread_docscreate_pr_draft
5. 高副作用动作必须 ask。 发邮件、推代码、部署、删库、改 IAM 都要人工确认。
6. 沙箱是第二道防线。 工具策略防“能不能调用”,沙箱防“即使调用了能碰到什么”。
7. RAG 和工具结果都不可信。 外部内容不能提升权限,不能覆盖系统策略,不能直接驱动敏感工具。
一句话概括:
成熟 Agent 的安全控制,不是让模型“学会听话”,而是让运行时具备“即使模型不听话也做不了坏事”的能力。
回到首页