SDK 把安全拆成四道:权限模式、工具白名单、路径限制、成本上限。 它们是串联的,前面拦住后面就不看了。 实测六个动作拦住四个,分布在后三道。而「改 .env」四道全过——四道管的是越界,不管敏感。
上一节是你自己写的拦截,这一节是它自带的那几道。 这一节的结论有点扎心:四道防线里有一道要你自己写,而且那道恰好管得最细。
一、四道各管什么
一 权限模式:这次是只读还是能动手。粗粒度,也最可靠。 二 工具白名单:哪几个工具能用。给了 Read,就等于能读所有能读的路径。 三 路径限制:工具能碰哪些路径。这一道选项里没有,得自己写。
四 成本上限:最多跑几轮、花多少。前三个都过了,它可能是第两百轮才出问题。 四道各管一个维度:态度、工具、目标、时长。缺一个就有一类事没人管。
二、真跑:六个动作逐个过四道
演示里六个动作:读项目内文件、写 /etc/passwd、跑 rm -rf、改 .env、读上级目录、第 16 次调用。 结果拦住四个:两个路径越界、一个工具不在白名单、一个轮数超上限。 第一道一个都没拦——因为这次用的是能动手的模式。它像总闸:切成只读,后面三道大部分都用不上。
还有一条要看清:「改 .env」四道全过了。它在项目内、Edit 也在白名单里。 所以四道防线管的是「越界」,不管「敏感」——敏感文件得靠 8.7 节那种钩子单独拦。
三、为什么是四道
权限模式管「整体态度」。它最粗,但最不容易被绕过:只读就是只读。 白名单管「用什么」。它挡的是「能力过宽」:不需要跑命令,就别给 Bash。 路径限制管「对谁」。这是白名单管不到的:给了 Edit 不等于该给所有文件。
成本上限管「多久」。它挡的是「跑不完还一直跑」,这是最贵的一种失败。 四个维度正交:任意一个失效,另外三个还在。这就是「纵深」的意思。
四、顺序为什么不能换
如果成本上限放最前面,你会先看到「轮数超了」,而真正的原因是它一直在试一个被拦的路径。 所以顺序该按「谁最能说明问题」排:粗的先、细的后。 这也解释了为什么第一道是模式而不是白名单:模式决定的事更大。
反过来说,看到「轮数超了」这种错误,先别急着调大上限——先看看它在刷什么。
五、自己补第三道
现实写法:把项目根算成绝对路径,判断目标路径是不是它的子路径。 别用「字符串以项目根开头」判断——那条会被 ../ 绕过,也会把 myproject2 当成 myproject 的子目录。 要先把路径规范化(消掉 ../ 和符号链接)再比,这是这一道最容易写错的地方。
补完这一道,四道才齐。而补它的成本,比事后处理一次越界写盘小得多。
六、动手 Demo:六个动作,四道防线各拦下几个
SDK 把安全拆成四道:权限模式、工具白名单、路径限制、成本上限。 它们是串联的:前面拦住,后面就不看了。六个动作逐个过一遍。
if turns > 15: gate = 4 # 成本上限
elif path.startswith(u"/") or path.startswith(u".."): gate = 3 # 路径越界
elif tool not in ALLOW: gate = 2 # 工具白名单
else: gate = 0 # 全过
实跑输出:
--------------------------------------------------------------------
六个动作,四道防线各拦下几个
--------------------------------------------------------------------
SDK 把安全拆成四道:权限模式、工具白名单、路径限制、成本上限。
它们是串联的:前面拦住,后面就不看了。所以顺序决定了你会看到哪条错误。
① 四道防线各管什么
--------------------------------------------------------------------
| 防线 | 管什么 | 落在哪 |
|---|---|---|
| 一 权限模式 | 它整体是只读还是能动手 | plan、default、acceptEdits |
| 二 工具白名单 | 哪几个工具能用 | allowed_tools |
| 三 路径限制 | 工具能碰哪些路径 | 在工具实现或钩子里判断 |
| 四 成本上限 | 最多跑几轮、花多少 | max_turns、预算 |
注意第三道不在选项里——它得自己写。这是四道里最容易漏的一道。
② 真跑:六个动作逐个过四道
--------------------------------------------------------------------
| 动作 | 被哪道拦 | 原因 |
|---|:---:|---|
| 读 src/app.py | 通过 | 全过 |
| 写 /etc/passwd | 第 3 道 | 路径在项目外 |
| 跑 rm -rf build | 第 2 道 | 工具不在白名单 |
| 改 .env | 通过 | 全过 |
| 读 ../other/x.py | 第 3 道 | 路径在项目外 |
| 又跑了第 16 次调用 | 第 4 道 | 轮数超上限 |
六个动作里 4 个被拦,分布在第二、三、四道各 1、2、1 个。
第一道一个都没拦——因为这次用的是能动手的模式。它是「总闸」:切成只读,后面三道大部分都用不上了。
还有一条要看清:「改 .env」四道全过了。它在项目内、Edit 也在白名单里。
所以四道防线管的是「越界」,不管「敏感」——敏感文件得靠钩子单独拦(8.7 节)。
③ 四道的分工为什么是四道
--------------------------------------------------------------------
权限模式管「整体态度」:这次是看还是改。它是粗粒度的,也最可靠。
白名单管「用什么」:给了 Read 就等于能读所有能读的路径。
路径限制管「对谁」:这是白名单管不到的那一层。
成本上限管「多久」:前三个都过了,它可能是第两百轮才出问题。
四道各管一个维度,缺一个就有一类事没人管。
④ 顺序为什么不能换
--------------------------------------------------------------------
如果成本上限放最前面,你会先看到「轮数超了」,而真正的原因是它一直在试一个被拦的路径。
所以顺序该按「谁最能说明问题」排:粗的先、细的后。
这也解释了为什么第一道是模式而不是白名单:模式决定的事更大。
⑤ 自己补第三道
--------------------------------------------------------------------
路径限制的现实写法:把项目根算成绝对路径,然后判断目标路径是不是它的子路径。
别用「字符串以项目根开头」判断——那条判断会被 ../ 绕过。
要先把路径规范化再比,这是这一道最容易写错的地方。
! 四道的划分是这一课的归纳,真实实现里它们可能由不同机制提供。
①四道:权限模式(整体态度)、工具白名单(用什么)、路径限制(对谁)、成本上限(多久)。 四道各管一个维度,正交。 ②六个动作拦住四个:两个路径越界、一个工具不在白名单、一个轮数超上限。 第一道一个都没拦,因为这次用的是能动手的模式。 ③「改 .env」四道全过——它在项目内、Edit 也在白名单里。 所以四道管的是「越界」,不管「敏感」,敏感文件得靠钩子单独拦。 ④第三道选项里没有,得自己写:把项目根算成绝对路径,判断目标是不是它的子路径。 别用字符串前缀判断,会被 ../ 绕过。
30 秒实验
- 把权限模式切成只读,重跑一遍。六个动作里有几个连第二道都到不了?这说明第一道的价值在哪?
- 把 ALLOW 里加上 Bash,重跑一遍。rm -rf 那个动作会被哪一道拦?如果四道都拦不住,还差什么?
- 把路径判断从「以 / 或 .. 开头」改成「字符串以项目根开头」,重跑一遍。哪个动作能绕过它?
常见误区
- 以为配了白名单就安全。白名单只管「用哪个工具」,不管「对哪个文件用」。
- 不写路径限制。四道里只有这一道管「对谁」,其他人管不到。
- 用字符串前缀判断路径是否越界。会被 ../ 和同名目录绕过。
- 把成本上限当成性能参数。它是安全防线:跑不完还一直跑,是最贵的一种失败。
- 把顺序调成「先查成本」。你会先看到「轮数超了」,而真正的原因在别处。
自测三问(点开对答案)
1. 四道防线分别是什么? —— 权限模式、工具白名单、路径限制、成本上限。四道各管一个维度,串联生效。 2. 为什么「改 .env」四道全过? —— 因为它在项目内、Edit 也在白名单里。 四道管的是「越界」,不管「敏感」——敏感文件要靠钩子单独拦。 3. 路径限制该怎么写? —— 把项目根算成绝对路径,规范化目标路径后判断是不是它的子路径。 不能用字符串前缀判断,会被 ../ 绕过。防线齐了,下一节换个方向:让它输出的东西能被程序直接读。
- ☐ (本篇完,下一篇 8.9 结构化输出:强制 JSON Schema)
相关笔记
- Agent SDK 中的 Hooks:钩子能补上「敏感文件」这一道
- 结构化输出:结构化输出
- Claude Code 橙皮书 · 索引
- 🐎 Claude Code 实战 · 索引