Claude Code 权限分析器为什么必须 Fail Closed:v2.1.214 暴露的 5 类边界 + 6 类不能推出的结论
Claude Code 权限分析器为什么必须 Fail Closed(2026)
TL;DR
- 场景:Claude Code v2.1.214(2026-07-18 01:20 UTC)在一个版本里集中修复了 7 类权限分析边界:路径 Glob 错误匹配、Windows PowerShell 5.1 Permission Check Bypass、Bash 文件描述符重定向解析差异、超长命令、zsh 条件表达式中的变量修饰符、
help/man危险选项、远程 Daemon 参数、本地/远程 Session 审批时序;v2.1.215(2026-07-19 02:56 UTC)随后停止自动运行/verify和/code-review,改为显式调用。 - 结论:这些修复不能被简单概括为"加了几个黑名单"。Coding Agent 的权限系统面对的是编译器前端与 Policy Engine 的组合问题——原始字符串必须按目标 Shell 解析、规范化、识别副作用,再与规则和运行时隔离联合决策。最重要的安全不变量是:
Unknown Syntax → Assume Harmless等于把解析器的不确定性转化为执行权限。 - 产出:覆盖路径作用域 / Bash 重定向 / PowerShell 版本 / 远程 Daemon / 审批时序五类边界,Shell-Aware Parser + 副作用分类 + Policy Evaluation + Runtime Audit 四段式控制平面,Fail Closed 三层策略(可证明安全 / 不确定 / 明确高风险),Approval Fatigue 缓解与跨 Shell 回归测试矩阵,可作为 Coding Agent 权限系统设计与验收蓝本。
版本矩阵
| 功能 | 状态 | 说明 |
|---|---|---|
| Claude Code v2.1.214 发布时间 2026-07-18 01:20 UTC,commit 07dcb0e | ✅ 已验证 | GitHub Releases 原文 + 网页 metadata 直接确认 |
修复单段dir/**规则(如Edit(src/**))自动批准项目树中任意位置同名dir/目录 | ✅ 已验证 | GitHub Releases v2.1.214 原文第一条 |
| 修复 Windows PowerShell 5.1 会话下的 Permission Check Bypass | ✅ 已验证 | GitHub Releases v2.1.214 原文第二条 |
| Bash 权限检查在 FD 重定向(分析器与 Bash 解析差异)上 Fail Closed | ✅ 已验证 | GitHub Releases v2.1.214 原文第三条 |
| 超过 10,000 字符的超长命令改为总是弹窗,不再自动运行 | ✅ 已验证 | GitHub Releases v2.1.214 原文第四条 |
zsh[[ ]]条件中的变量下标与修饰符不再被当作惰性文本 | ✅ 已验证 | GitHub Releases v2.1.214 原文第五条 |
help/man携带危险选项、命令替换、反斜杠路径时不再自动通过 | ✅ 已验证 | GitHub Releases v2.1.214 原文第六条 |
Docker / Podmandockershim 携带--url/--connection/--identity/ Podman remote 时补齐权限提示 | ✅ 已验证 | GitHub Releases v2.1.214 原文 |
| 远程 Session 权限请求不再在本地确认前提前执行 | ✅ 已验证 | GitHub Releases v2.1.214 原文 |
OpenTelemetry 增加message.uuid/client_request_id/tool_source字段 | ✅ 已验证 | GitHub Releases v2.1.214 原文 |
CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH配置 60KB 截断 | ✅ 已验证 | GitHub Releases v2.1.214 原文 |
| Claude Code v2.1.215 发布时间 2026-07-19 02:56 UTC,commit 015170d | ✅ 已验证 | GitHub Releases 原文 |
v2.1.215 停止自动运行/verify和/code-review,需用户显式调用 | ✅ 已验证 | GitHub Releases v2.1.215 原文 |
官方权限规则评估顺序Deny → Ask → Allow,第一条匹配规则决定结果 | ✅ 已验证 | 官方 Permissions 文档 S2 |
| 权限由 Claude Code 执行,不是由模型自行决定 | ✅ 已验证 | 官方 Permissions 文档 S2 |
| Bash 执行可使用 OS 级文件系统和网络隔离 | ✅ 已验证 | 官方 Sandboxing 文档 S3 |
| 不存在对应 CVE 或公开 Security Advisory | ⚠️ 未公开 | GitHub Releases 只描述 fix,未配 CVE 编号 |
摘要
Claude Code v2.1.214 在一个版本中修复了多种权限分析边界:路径 Glob 错误匹配、Windows PowerShell 5.1 Permission Check Bypass、Bash 文件描述符重定向解析差异、zsh 条件表达式中的变量修饰符、远程 Daemon 参数、超长命令和本地/远程 Session 审批时序。v2.1.215 随后停止自动运行/verify和/code-review,改为显式调用。[S1]
这些修复不能被简单概括为“加了几个黑名单”。它们说明 Coding Agent 的权限系统面对的是编译器前端与 Policy Engine 的组合问题:原始字符串必须按目标 Shell 解析、规范化、识别副作用,再与规则和运行时隔离进行联合决策。
最重要的安全不变量是:
Analyzer Can Prove Safe → Auto Allow Analyzer Is Unsure → Ask Analyzer Detects Risk → Deny or Sandbox任何Unknown Syntax → Assume Harmless都是在把解析器的不确定性转化为执行权限。
1. 权限分析器真正要判断什么
用户批准的不是一串字符,而是一个预期语义:读取某个文件、运行某个测试、连接某个服务或修改某个目录。Shell 接收字符后还会执行:
- Tokenization;
- 引号和转义;
- 变量展开;
- Glob;
- 命令替换;
- 重定向;
- 管道和条件执行;
- 子 Shell;
- 平台特定语法;
- 外部命令自身的参数解析。
权限分析器若只做字符串前缀匹配,可能把“看起来只读”的命令交给 Shell,而 Shell 执行的是另一套语义。
2. v2.1.214 暴露的五类边界
2.1 路径作用域与 Canonicalization
Edit(src/**)曾可能自动批准项目树中其他位置的同名嵌套目录。根因不是src这个字符串,而是规则中的相对路径应绑定哪个基准目录。
安全评估需要先确定:
Rule Path → Resolve Against CWD / Project Root → Normalize . and .. → Resolve Symlink Policy → Compare Canonical Target同名目录、Git Worktree、Symlink、Hard Link 和 Bind Mount 都会让“逻辑路径”与“实际对象”分离。
2.2 Bash 重定向与解析差异
Bash 的文件描述符重定向、复合命令和条件组合可以改变数据流和副作用。Release 明确说明,某些 FD Redirect 形式在 Claude Code 与 Bash 中解析不同,因此改为 Fail Closed。[S1]
关键不是枚举全部危险字符,而是建立 Parser Differential:
- 权限分析器输出规范化 AST;
- 目标 Shell 输出自己的解析结果;
- 两者不能证明等价时,不自动放行。
2.3 PowerShell 版本与不可见语义
PowerShell 5.1 与 PowerShell 7 在解析、编码和命令行为上并不完全一致。Release 确认修复了 Windows PowerShell 5.1 的 Permission Check Bypass。[S1] 后续版本还继续处理不可见 Unicode 和网络路径等边界。
权限判断必须绑定:
- Shell 类型;
- Shell 版本;
- 操作系统;
- 编码;
- 执行策略;
- 当前 Provider 和路径语义。
“PowerShell 命令”不是一个稳定语法集合。
2.4 远程 Daemon 改变执行边界
Docker、Podman 等命令看似在操作本地容器,但--url、--connection、--identity或远程模式可能把操作发送到另一台主机。权限系统如果只按命令名分类,会把本地风险模型错误应用到远程资产。
需要把目标执行域纳入 Policy:
Local CLI → Endpoint Resolution → Local / Remote / Unknown → Identity and Credential → Resource Scope → Approval Decision2.5 审批时序与 Remote Session
Release 还修复了远程 Session 的权限请求可能早于本地确认继续执行的问题。[S1] 这属于分布式状态机:请求、展示、确认、执行和审计必须具有一致顺序,不能让两个 Session 对同一次操作形成不同状态。
3. 官方权限模型给出的基础框架
Claude Code 官方文档把权限规则分为deny、ask和allow,评估顺序为:
Deny → Ask → Allow第一条匹配规则决定结果;权限由 Claude Code 执行,而不是由模型自行决定。[S2]
这带来三个设计结论:
- Prompt、CLAUDE.md 或 AGENTS.md 只能表达行为偏好,不能替代执行权限。
- Deny 是硬边界,Ask 是人工节点,Allow 只应覆盖可证明的低风险范围。
- 规则顺序、范围和路径基准都必须可测试。
官方 Sandbox 文档进一步说明,Bash 执行可使用 OS 级文件系统和网络隔离。[S3] 权限分析与 Sandbox 不是替代关系:
- Analyzer 决定是否允许尝试;
- Sandbox 限制即使执行也能触达的资源;
- Audit 记录实际发生了什么。
4. 正确的控制平面
Raw Command ↓ Shell and Version Selection ↓ Shell-Aware Parser ↓ Normalized AST ↓ Path / Endpoint Resolution ↓ Side-Effect Classification ↓ Policy Evaluation: Deny / Ask / Allow ↓ OS Sandbox and Credential Scope ↓ Execution ↓ Runtime Audit and Result Classification4.1 Shell-Aware Parser
至少输出命令、参数、重定向、管道、条件分支、子命令和变量引用。不能理解的节点标记为UNKNOWN,而不是丢弃。
4.2 Side-Effect Classification
副作用不只分读写。建议分类:
- 本地只读;
- 本地写入;
- 删除或不可逆;
- 网络访问;
- 凭据访问;
- 进程/服务控制;
- 容器/虚拟化控制;
- 远程执行;
- 代码加载;
- 未知。
4.3 Policy Evaluation
Policy 需要同时引用:
- 规范化 AST;
- Canonical Path;
- Endpoint;
- Tool Source;
- Session/用户身份;
- Repository Trust;
- Sandbox Profile;
- 风险等级。
4.4 Runtime Audit
OpenTelemetry 中增加message.uuid、client_request_id和tool_source,为把模型消息、用户请求与工具来源串成 Trace 提供了基础。[S1] 企业审计应进一步记录:
- 决策规则 ID;
- 原始与规范化命令哈希;
- 批准者;
- Sandbox Profile;
- 实际文件和网络副作用;
- Exit Code;
- 结果摘要;
- 回滚状态。
5. Fail Closed 不等于所有命令都弹窗
Fail Closed 的目标不是制造审批疲劳,而是让不确定语义不能自动跨越权限边界。
更合理的三层策略:
可证明安全
例如固定工作区内的明确只读操作、无网络、无外部脚本加载、无重定向。可自动允许。
不确定
含未知语法、超长命令、动态变量、远程目标、复杂重定向、命令替换。转入 Ask。
明确高风险
删除、凭据导出、远程 Daemon、宿主机 Socket、系统目录写入、执行下载内容。Deny 或只在隔离环境中允许。
减少弹窗的正确方法是缩小 Agent 能力面、提供更精确的 Tool、使用预批准的任务模板和强 Sandbox,而不是把未知语法默认安全。
6. Approval Fatigue
Ask 不是万能控制。用户可能连续点击批准,甚至无法从长命令中识别真实副作用。审批界面必须展示“语义摘要”,而不是只展示原始字符串:
Action: Write files Scope: /workspace/src/** Network: none Credentials: none Remote target: none Irreversible: no Reason: run formatter on generated files Policy: ask-write-workspace对复杂命令,界面还应显示展开后的路径、远程端点、重定向目标和外部脚本来源。
7. 跨 Shell 回归测试
Permission Analyzer 应拥有类似编译器的测试矩阵:
| 维度 | 示例 |
|---|---|
| Shell | Bash、zsh、PowerShell 5.1、PowerShell 7 |
| OS | Linux、macOS、Windows |
| Path | 相对、绝对、..、Symlink、UNC、Worktree |
| Syntax | 引号、变量、重定向、管道、条件、子命令 |
| Endpoint | 本地、远程、未知 |
| Length | 正常、超长、截断边界 |
| Encoding | ASCII、Unicode、不可见字符 |
| Expected | Allow、Ask、Deny、Parse Error |
测试必须同时断言:规范化 AST、副作用分类、规则匹配和最终决策。
8. 与 MCP 和 Plugin Trust 的共同模型
命令审批和 MCP/Plugin Trust 共享同一个原则:批准对象必须是可识别的具体工件,而不是一个永久可信的名字。
Code / Config / Assets → Canonical Manifest → Fingerprint → Approval Record → Runtime Verification → Allow / Reapprove / Block权限规则、Plugin 版本、MCP 资源和 Sandbox Profile 都应进入审批记录。任何影响执行语义的变化都应触发重新评估。
9. 不能从 Release 推出的结论
- 没有证据说明每项修复都曾被真实攻击者利用。
- 没有找到对应 CVE 或公开 Security Advisory。
- 不能用“Bypass”一词自动推断严重等级。
- Ask Prompt 不能阻止用户无差别批准。
- Parser 修复不能替代 Sandbox、最小权限和网络隔离。
/verify、/code-review停止自动运行主要是可预测性与控制权变化,不应直接称为漏洞修复。
10. 结论
Coding Agent 的风险不是“AI 会不会写错命令”,而是运行时会不会把一个无法证明安全的语义自动当成低风险。权限分析器必须像编译器一样解析、像 Policy Engine 一样决策、像 Sandbox 一样约束、像可观测系统一样审计。
最小安全不变量保持不变:
Unknown is not Safe.来源
- [S1] Anthropic Claude Code GitHub Releases: https://github.com/anthropics/claude-code/releases
- [S2] Claude Code Permissions: https://code.claude.com/docs/en/permissions
- [S3] Claude Code Sandboxing: https://code.claude.com/docs/en/sandboxing
- [S4] Claude Code Auto Mode Configuration: https://code.claude.com/docs/en/auto-mode-config
- [S5] Claude Code Security: https://code.claude.com/docs/en/security
错误速查卡
| 症状 | 根因 | 定位 | 修复 |
|---|---|---|---|
Edit(src/**)自动批准了项目树外任意dir/目录的写 | 路径 Glob 解析时基准目录绑定错误,src/**被误匹配到任意位置同名目录 | 跑单段dir/**规则 + 嵌套目录测试;看 v2.1.214 之前的版本行为 | 升到 v2.1.214+;所有dir/**类规则改为<cwd>/dir/**或**/dir/**显式形式 |
Windows PowerShell 5.1 下whoami/Get-ChildItem等命令被静默放行 | PowerShell 5.1 与 7 的解析、编码、命令行为差异,5.1 下 Permission Check Bypass | 在 Win PS 5.1 跑权限敏感命令看是否提示 | 升到 v2.1.214+;对 PS 5.1 单独跑权限测试;尽量升级到 PS 7 |
Bash FD 重定向如bash -c "cmd > /dev/null"解析不一致 | 权限分析器与 Bash 对 FD 重定向的解析不同 | 跑 FD 重定向变体测试;看 v2.1.214 changelog | 升到 v2.1.214+;Parser Differential 测两者 AST 是否等价;不等价时拒绝或 Ask |
| 超长命令(10,000+ 字符)被自动放行 | 旧版本在超长命令上误判为安全 | 跑 10000+ 字符命令;看 v2.1.214 第 4 条 | 升到 v2.1.214+;Pipeline 强制超长命令走 Ask |
zsh[[ "$x" == ${y:-default} ]]被当作惰性文本 | 权限分析器未识别 zsh[[ ]]中的变量下标与修饰符 | 在 zsh 跑 zsh 特有条件;看 v2.1.214 第 5 条 | 升到 v2.1.214+;为 zsh[[ ]]单建测试集 |
man -P或help -s携带命令替换/反斜杠被静默放行 | 旧规则把help/man默认安全,但其参数可触发子进程 | 跑man -P "<cmd>"与help <subcommand>测试;看 v2.1.214 第 6 条 | 升到 v2.1.214+;对help/man强制走 Ask |
docker --url=tcp://remote:2375 ps自动放行到远程 Daemon | --url/--connection/--identity/ Podman remote 改写了目标执行域 | 跑远程 Daemon 参数测试;看 v2.1.214 相关条目 | 升到 v2.1.214+;对 docker / podman 携带 remote flag 强制 Ask 并要求人工确认 Endpoint |
| 远程 Session 在本地确认前提前执行了命令 | 远程 Session 与本地 Session 状态机不一致 | 跑 Remote Session 权限请求时序测试;看 v2.1.214 相关条目 | 升到 v2.1.214+;分布式状态机必须保证请求-展示-确认-执行-审计一致性 |
/verify//code-review在不需要时自动跑 | 旧版本允许 Claude 自主决定调用 review 类 skill | 看 session 行为;查 v2.1.215 变更 | 升到 v2.1.215+;这两个 skill 必须用户显式调用 |
| 只看命令字符串前缀就放行,实际语义不同 | 权限分析器只做字符串前缀匹配,未做 Shell 解析 | 跑同一前缀不同语义的命令对;看是否都被放行 | 引入 Shell-Aware Parser + Parser Differential;不等价时拒绝或 Ask |
| 审批弹窗只显示原始长字符串,用户连续点批准 | Approval Fatigue + 缺少语义摘要 | 用户操作审计;Ask 节点统计 | 审批界面展示 Action / Scope / Network / Credentials / Remote / Irreversible 等结构化字段 |
| Parser 修复后直接当作 Sandboxing 替代 | 两者解的是不同层问题,Analyzer 决定"是否允许尝试",Sandbox 决定"即使执行能触达什么" | 检查部署架构是否同时有 Analyzer + Sandbox | 两者必须叠加使用,不能互相替代 |
| 修改权限规则后没有重测 Analyzer 行为 | 规则顺序、范围、路径基准变了,Analyzer 行为可能改变 | CI 上跑跨 Shell 回归测试矩阵 | 把 8 维测试矩阵加入 CI,改动规则必须全绿 |
| OpenTelemetry 字段不足以串联 Trace | 缺少message.uuid/client_request_id/tool_source | 检查 OTel 配置与字段映射 | 升 v2.1.214+ 增加三字段;企业审计在此基础上加决策规则 ID、批准者、Exit Code、回滚状态 |
| Prompt / CLAUDE.md / AGENTS.md 当作权限来用 | 这些只能表达偏好,不能替代执行权限 | 看权限是否在 Claude Code 执行层而非模型自决 | 把权限决策收敛到 Claude Code 执行层,Prompt 层只表达行为偏好 |
