推荐标题:Claude Code 权限分析器为什么必须 Fail Closed 备选标题1:别只看表面:Claude Code 权限分析器为什么必须 Fail Closed真正要验收什么 备选标题2:一张工程图拆解 Claude Code 权限分析器为什么必须 Fail Closed 备选标题3:Claude Code 权限分析器为什么必须 Fail Closed为什么经常被理解错


摘要
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 Decision
2.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 Classification
4.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