第五章:权限与安全——信任的边界
“Agent 能做什么,不能做什么,由权限系统说了算。它是 Claude Code 最重要的安全护城河。”
5.1 为什么需要权限系统
Claude Code 是一个能够直接操作文件系统、执行 Shell 命令、访问网络的 AI Agent。一旦模型被注入恶意指令(prompt injection)、生成错误操作、或在 bypassPermissions 模式下运行,后果可能是灾难性的。
权限系统的核心目标:
目标
说明
最小权限原则
Agent 默认只能操作当前工作目录,不能越界
可审计性
每条权限决策都有 decisionReason,可溯源
可配置性
用户、项目、企业策略均可独立配置规则
防御纵深
规则检查 → 沙箱隔离 → AI 分类器 三层叠加
透明度
向用户实时解释"为什么需要这个权限"
5.2 全局架构:三道防线
graph TB
subgraph L1["第一道防线:权限规则引擎"]
A1[ToolPermissionContext] --> A2[规则匹配 allow/deny/ask]
A2 --> A3[PermissionDecision]
end
subgraph L2["第二道防线:OS 沙箱隔离"]
B1[SandboxManager] --> B2[bubblewrap/Sandbox]
B2 --> B3[文件系统 + 网络隔离]
end
subgraph L3["第三道防线:AI 分类器"]
C1[yoloClassifier] --> C2[Claude Haiku 推理]
C2 --> C3[shouldBlock 决策]
end
ToolCall --> L1
L1 -->|ask| UserDialog
L1 -->|allow| L2
L2 -->|violation| L3
L3 -->|block| Abort
L3 -->|pass| Execute
三道防线各司其职:
第一道 :规则引擎,基于配置文件的静态匹配,速度最快
第二道 :操作系统级沙箱,隔离进程,阻止越权文件/网络访问
第三道 :AI 分类器(Auto Mode),对高风险操作做语义理解
5.3 权限模式(PermissionMode)
src/types/permissions.ts 定义了五种外部可用模式:
1 2 3 4 5 6 7 export const EXTERNAL_PERMISSION_MODES = [ 'acceptEdits' , 'bypassPermissions' , 'default' , 'dontAsk' , 'plan' , ] as const
除此之外还有两个内部模式:
模式
说明
使用场景
auto
启用 AI 分类器自动决策
通过 TRANSCRIPT_CLASSIFIER feature flag 开启
bubble
向上游传递权限请求
子 Agent 向父 Agent 冒泡
模式优先级 (从高到低):
1 bypassPermissions > dontAsk > acceptEdits > default > plan
5.4 权限规则体系
4.1 规则数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type PermissionRuleSource = | 'userSettings' | 'projectSettings' | 'localSettings' | 'flagSettings' | 'policySettings' | 'cliArg' | 'command' | 'session' type PermissionBehavior = 'allow' | 'deny' | 'ask' type PermissionRuleValue = { toolName: string ruleContent?: string } type PermissionRule = { source: PermissionRuleSource ruleBehavior: PermissionBehavior ruleValue: PermissionRuleValue }
4.2 规则字符串格式
权限规则以字符串形式存储在配置文件,格式为:
1 2 3 4 5 ToolName # 工具级规则,匹配该工具所有调用 ToolName(content) # 内容级规则,匹配特定参数 Bash(npm install) # 匹配 "npm install" 开头的 Bash 命令 Edit(src/**) # 匹配 src/ 目录下的文件编辑 WebFetch(domain:github.com) # 匹配访问 github.com
permissionRuleParser.ts 实现了解析逻辑,特别处理括号转义:
1 2 3 4 5 6 escapeRuleContent('psycopg2.connect()' ) permissionRuleValueFromString('Bash(python -c "print\\(1\\)")' )
5.5 权限决策流程
5.1 决策结果类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 type PermissionDecision = | PermissionAllowDecision | PermissionAskDecision | PermissionDenyDecision type PermissionAllowDecision = { behavior: 'allow' updatedInput?: Input userModified?: boolean decisionReason?: PermissionDecisionReason acceptFeedback?: string contentBlocks?: ContentBlockParam[] } type PermissionAskDecision = { behavior: 'ask' message: string suggestions?: PermissionUpdate[] blockedPath?: string pendingClassifierCheck?: PendingClassifierCheck isBashSecurityCheckForMisparsing?: boolean }
5.2 决策原因溯源
每个决策都携带 PermissionDecisionReason,支持 9 种原因类型:
1 2 3 4 5 6 7 8 9 10 11 12 type PermissionDecisionReason = | { type : 'rule' ; rule: PermissionRule } | { type : 'mode' ; mode: PermissionMode } | { type : 'subcommandResults' ; reasons: Map<...> } | { type : 'permissionPromptTool' ; ... } | { type : 'hook' ; hookName: string ; ... } | { type : 'asyncAgent' ; reason: string } | { type : 'sandboxOverride' ; ... } | { type : 'classifier' ; classifier: string ; ... } | { type : 'safetyCheck' ; classifierApprovable: boolean ; ... } | { type : 'workingDir' ; reason: string } | { type : 'other' ; reason: string }
这种设计让每个权限决策都 完全可解释、可追溯 。
5.3 决策流程状态机
stateDiagram-v2
[*] --> RuleCheck: 工具调用
RuleCheck --> AllowDecision: 命中 allow 规则
RuleCheck --> DenyDecision: 命中 deny 规则
RuleCheck --> AskDecision: 命中 ask 规则
RuleCheck --> ModeCheck: 无匹配规则
ModeCheck --> AllowDecision: bypassPermissions/dontAsk
ModeCheck --> AskDecision: default
ModeCheck --> DenyDecision: plan(写操作)
ModeCheck --> ClassifierCheck: auto 模式
ClassifierCheck --> AllowDecision: shouldBlock=false
ClassifierCheck --> AskDecision: shouldBlock=true
AskDecision --> UserDialog: 展示权限对话框
UserDialog --> AllowDecision: 用户批准
UserDialog --> DenyDecision: 用户拒绝
UserDialog --> UpdateRules: 用户选择"始终允许"
AllowDecision --> Execute: 执行工具
DenyDecision --> [*]: 返回错误信息
5.6 配置来源与加载优先级
6.1 设置文件层次
1 2 3 4 5 6 7 优先级(高→低): policySettings ← 企业管控(只读,不可覆盖) flagSettings ← CLI flag 注入(--permission-mode 等) localSettings ← .claude/settings.local.json(本地,不提交 git) projectSettings ← .claude/settings.json(项目级,可提交 git) userSettings ← ~/.claude/settings.json(用户全局)
6.2 配置文件结构示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 { "permissions" : { "allow" : [ "Bash(npm run test:*)" , "Bash(git status)" , "Edit(src/**)" , "WebFetch(domain:github.com)" ], "deny" : [ "Bash(rm -rf *)" , "Edit(/etc/**)" ], "ask" : [ "Bash(git push*)" ] } }
6.3 loadAllPermissionRulesFromDisk 加载逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export function loadAllPermissionRulesFromDisk ( ): PermissionRule [] { if (shouldAllowManagedPermissionRulesOnly()) { return getPermissionRulesForSource('policySettings' ) } const rules: PermissionRule[] = [] for (const source of getEnabledSettingSources()) { rules.push(...getPermissionRulesForSource(source)) } return rules }
关键设计 :allowManagedPermissionRulesOnly 启用时,用户无法自行添加权限规则,强制企业合规。
5.7 权限上下文(ToolPermissionContext)
工具执行时携带的完整权限上下文:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 type ToolPermissionContext = { readonly mode: PermissionMode readonly additionalWorkingDirectories: ReadonlyMap<string , AdditionalWorkingDirectory> readonly alwaysAllowRules: ToolPermissionRulesBySource readonly alwaysDenyRules: ToolPermissionRulesBySource readonly alwaysAskRules: ToolPermissionRulesBySource readonly isBypassPermissionsModeAvailable: boolean readonly strippedDangerousRules?: ToolPermissionRulesBySource readonly shouldAvoidPermissionPrompts?: boolean readonly awaitAutomatedChecksBeforeDialog?: boolean readonly prePlanMode?: PermissionMode }
5.8 危险规则检测机制
8.1 什么是"危险规则"
在 Auto Mode(AI 分类器模式)下,某些宽泛的 allow 规则会绕过分类器,导致任意代码执行。permissionSetup.ts 实现了危险规则检测:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 isDangerousBashPermission('Bash' , undefined ) isDangerousBashPermission('Bash' , '*' ) isDangerousBashPermission('Bash' , 'python:*' ) isDangerousBashPermission('Bash' , 'node *' ) isDangerousBashPermission('Bash' , 'npm test' ) isDangerousPowerShellPermission('PowerShell' , 'invoke-expression' ) isDangerousPowerShellPermission('PowerShell' , 'start-process' ) isDangerousTaskPermission('Agent' , undefined )
8.2 危险解释器黑名单
dangerousPatterns.ts 维护了跨平台危险解释器列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 export const CROSS_PLATFORM_CODE_EXEC = [ 'python' , 'python3' , 'python2' , 'node' , 'deno' , 'tsx' , 'ruby' , 'perl' , 'php' , 'lua' , 'npx' , 'bunx' , 'npm run' , 'yarn run' , 'pnpm run' , 'bun run' , 'bash' , 'sh' , 'ssh' , ] export const DANGEROUS_BASH_PATTERNS = [ ...CROSS_PLATFORM_CODE_EXEC, 'zsh' , 'fish' , 'eval' , 'exec' , 'env' , 'xargs' , 'sudo' , ]
8.3 Auto Mode 入口的规则清洗
进入 Auto Mode 时,系统会自动剥离危险规则,防止"allow 规则绕过分类器"攻击:
flowchart LR
A[用户配置规则] --> B{isDangerousClassifierPermission?}
B -->|危险| C[strippedDangerousRules\n记录但不生效]
B -->|安全| D[正常加入 alwaysAllowRules]
C --> E[Auto Mode 下通知用户\n规则已被临时移除]
5.9 沙箱系统(SandboxManager)
9.1 沙箱架构
sandbox-adapter.ts 将 @anthropic-ai/sandbox-runtime 与 Claude Code 的配置系统集成:
graph LR
subgraph ClaudeCode["Claude Code 层"]
CC1[SandboxManager] --> CC2[convertToSandboxRuntimeConfig]
CC2 --> CC3[SandboxRuntimeConfig]
end
subgraph OSLayer["OS 沙箱层 @anthropic-ai/sandbox-runtime"]
OS1[BaseSandboxManager] --> OS2[bubblewrap / macOS Sandbox]
OS2 --> OS3[文件系统挂载]
OS2 --> OS4[网络过滤]
end
CC1 -->|委托| OS1
CC3 -->|配置| OS1
9.2 沙箱配置转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 function convertToSandboxRuntimeConfig (settings: SettingsJson ): SandboxRuntimeConfig { return { network: { allowedDomains, deniedDomains, allowUnixSockets, allowLocalBinding, }, filesystem: { allowWrite: ['.' , getClaudeTempDir(), ...additionalDirs], denyWrite: [ ...settingsPaths, '.claude/skills' , ], denyRead, allowRead, }, } }
9.3 安全硬编码
沙箱中有几处安全关键的强制规则 ,不受用户配置影响:
规则
原因
永远禁写 settings.json
防止沙箱内进程修改权限配置,实现沙箱逃逸
永远禁写 .claude/skills/
Skills 有与 commands 相同的高权限级别
防御裸 git 仓库注入
攻击者在 cwd 植入 HEAD/objects/refs 文件可触发 git fsmonitor hook
设置文件始终拒写
防止降级攻击(如删除 deny 规则)
9.4 git Worktree 感知
沙箱特殊处理 git worktree 场景:
1 2 3 4 5 6 7 async function detectWorktreeMainRepoPath (cwd: string ): Promise <string | null > { const gitContent = await readFile(join(cwd, '.git' ), 'utf8' ) const gitdirMatch = gitContent.match(/^gitdir:\s*(.+)$/m ) }
5.10 AI 分类器(yoloClassifier / Auto Mode)
10.1 分类器定位
Auto Mode 的分类器是第三道防线,对 default 模式下需要询问用户的操作,用 AI 自动判断是否安全:
sequenceDiagram
participant Tool as 工具调用
participant Perm as 权限引擎
participant Classifier as yoloClassifier
participant User as 用户
Tool->>Perm: 请求权限
Perm->>Perm: 规则检查 → ask
Perm->>Classifier: 发起异步分类
Note over Classifier: pendingClassifierCheck
alt 分类器先返回
Classifier->>Perm: shouldBlock=false
Perm->>Tool: allow(免打扰)
else 用户先响应
Perm->>User: 弹出权限对话框
User->>Perm: 批准/拒绝
end
10.2 两阶段分类器设计
YoloClassifierResult 揭示了两阶段(fast + thinking)架构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type YoloClassifierResult = { shouldBlock: boolean reason: string model: string usage?: ClassifierUsage stage?: 'fast' | 'thinking' stage1Usage?: ClassifierUsage stage1DurationMs?: number stage1RequestId?: string stage2Usage?: ClassifierUsage stage2DurationMs?: number transcriptTooLong?: boolean unavailable?: boolean }
两阶段策略 :
Stage 1(fast) :使用标准 Claude 模型快速判断,延迟低
Stage 2(thinking) :若 Stage 1 置信度不足,使用扩展思考(extended thinking)深度推理
降级 :transcriptTooLong=true 时,固定降级为询问用户,而非 fail-closed 拒绝
10.3 Auto Mode 自定义规则
用户可以在 settings.json 中自定义分类器的判断规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { "autoMode" : { "allow" : [ "Running npm test commands" , "Reading files in the project directory" ], "soft_deny" : [ "Pushing to remote git repositories" , "Modifying system configuration files" ], "environment" : [ "This is a development environment" , "The project uses TypeScript" ] } }
分类器将这些规则注入 system prompt 的特定标签位置(<user_allow_rules_to_replace> 等),实现个性化安全策略。
5.11 权限解释器(PermissionExplainer)
当权限对话框弹出时,Claude Code 会异步 使用 AI 生成人类可读的风险说明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 export async function generatePermissionExplanation ({ toolName, toolInput, messages, signal, } ): Promise <PermissionExplanation | null > { const response = await sideQuery({ model, tools: [EXPLAIN_COMMAND_TOOL], tool_choice: { type : 'tool' , name: 'explain_command' }, ... }) } type PermissionExplanation = { riskLevel: 'LOW' | 'MEDIUM' | 'HIGH' explanation: string reasoning: string risk: string }
关键设计 :
解释异步生成,不阻塞权限对话框弹出
使用 tool_choice: 'forced' 强制结构化输出,避免格式解析失败
注入近期 3 条对话消息作为上下文,让 “reasoning” 更准确
用户可通过 permissionExplainerEnabled: false 关闭此功能
5.12 企业管控策略(Policy Settings)
12.1 企业管控能力矩阵
功能
配置字段
说明
只使用策略规则
allowManagedPermissionRulesOnly
用户无法自行添加 allow 规则
只使用策略沙箱域名
sandbox.network.allowManagedDomainsOnly
用户无法访问未批准域名
只使用策略文件读路径
sandbox.filesystem.allowManagedReadPathsOnly
限制文件读取范围
远程配置安全检查
checkManagedSettingsSecurity()
危险配置变更须用户确认
12.2 远程管控安全检查
企业可以通过 API 下发托管配置(policySettings)。当配置中包含危险设置时,会触发用户确认对话框:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 export async function checkManagedSettingsSecurity ( cachedSettings: SettingsJson | null , newSettings: SettingsJson | null , ): Promise <SecurityCheckResult > { if (!hasDangerousSettings(extractDangerousSettings(newSettings))) { return 'no_check_needed' } if (!hasDangerousSettingsChanged(cachedSettings, newSettings)) { return 'no_check_needed' } if (!getIsInteractive()) return 'no_check_needed' }
安全理念 :企业配置的变更如果引入危险权限,必须通过用户再次确认 ,即使是授权管理员也无法静默推送危险配置。
5.13 工作目录权限边界
13.1 路径验证机制
Claude Code 的文件工具(FileRead/FileEdit)在执行前会验证路径是否在允许的工作目录内:
flowchart TD
A[文件路径请求] --> B{路径在 cwd 内?}
B -->|是| C[允许]
B -->|否| D{路径在 additionalWorkingDirectories?}
D -->|是| C
D -->|否| E{有匹配的 allow 规则?}
E -->|是| C
E -->|否| F{decisionReason.type === 'workingDir'}
F --> G[生成 ask 决策\n提示用户添加目录]
13.2 路径前缀约定
沙箱中的路径规则支持特殊前缀:
前缀
含义
示例
//path
绝对路径(双斜杠转义)
//.aws/** → /.aws/**
/path
相对于 settings 文件目录
/src/** → $PROJECT/.claude/../src/**
~/path
Home 目录(透传给沙箱运行时)
~/.ssh/config
./path
相对路径
./dist/**
13.3 临时目录
Claude Code 维护一个专用临时目录用于内部操作(Shell cwd 跟踪文件等):
1 2 3 4 function getClaudeTempDir ( ): string { return join(os.tmpdir(), 'claude-code-temp' ) }
5.14 权限更新操作
14.1 PermissionUpdate 操作类型
1 2 3 4 5 6 7 type PermissionUpdate = | { type : 'addRules' ; destination; rules; behavior } | { type : 'replaceRules' ; destination; rules; behavior } | { type : 'removeRules' ; destination; rules; behavior } | { type : 'setMode' ; destination; mode } | { type : 'addDirectories' ; destination; directories } | { type : 'removeDirectories' ; destination; directories }
14.2 规则持久化与编辑安全
permissionsLoader.ts 的 addPermissionRulesToSettings 使用双重降级策略:
1 2 3 4 5 const settingsData = getSettingsForSource(source) || getSettingsForSourceLenient_FOR_EDITING_ONLY_NOT_FOR_READING(source) || getEmptyPermissionSettingsJson()
设计意图 :即使 settings.json 中有 hooks 等字段格式错误,也不会导致已有权限规则丢失。宽松 loader 仅用于写入 ,绝不用于执行时读取(函数名中的 FOR_EDITING_ONLY 警告了这一点)。
5.15 权限 UI 组件体系
src/components/permissions/ 下有完整的 UI 组件树:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 permissions/ ├── PermissionRequest.tsx # 通用权限请求容器 ├── PermissionDialog.tsx # 权限对话框 ├── PermissionExplanation.tsx # AI 生成的风险说明展示 ├── PermissionDecisionDebugInfo.tsx # 调试信息:显示 decisionReason ├── BashPermissionRequest/ # Bash 命令专用对话框 │ ├── BashPermissionRequest.tsx # 展示命令、风险等级 │ └── bashToolUseOptions.tsx # "允许一次/始终允许/拒绝" 选项 ├── FileEditPermissionRequest/ # 文件编辑专用(含 diff 预览) ├── FileWritePermissionRequest/ # 文件写入专用(含内容预览) ├── WebFetchPermissionRequest/ # 网络请求专用 ├── AskUserQuestionPermissionRequest/ # AskUserQuestion 工具的专属 UI ├── ComputerUseApproval/ # Computer Use 审批 └── rules/ # 权限规则管理 UI ├── PermissionRuleList.tsx # 规则列表 ├── AddPermissionRules.tsx # 添加规则 └── RecentDenialsTab.tsx # 最近拒绝记录
每种工具调用都有专属的权限对话框 ,展示最相关的信息(如文件 diff、命令高亮、域名信息等)。
5.16 swarm 多 Agent 权限同步
src/utils/swarm/permissionSync.ts 处理多 Agent 协作场景下的权限同步:
sequenceDiagram
participant Parent as 主 Agent
participant Worker as Worker Agent
participant Perm as 权限系统
Worker->>Perm: 需要权限(behavior: ask)
Perm->>Parent: bubble 冒泡请求
Parent->>User: 弹出权限对话框
User->>Parent: 批准(始终允许)
Parent->>Perm: 写入 session 规则
Perm->>Worker: allow(规则已同步)
Note over Parent, Worker: 其他 Worker 复用同一规则
Worker Agent 无法自行修改全局规则,只能冒泡给父 Agent 处理。父 Agent 批准后,规则写入 session 来源,当前会话所有 Worker 共享。
5.17 设计原则总结
通过对权限系统的完整分析,可以提炼出 10 条核心设计原则:
#
原则
体现
1
Fail-Closed(失败关闭)
未匹配规则默认 ask,不默认 allow
2
最小权限
默认只能操作 cwd,越界需显式授权
3
纵深防御
规则引擎 + OS 沙箱 + AI 分类器三层
4
完全可审计
每个决策携带 decisionReason 溯源链
5
用户可见性
AI 解释器实时说明"为什么需要此权限"
6
企业管控优先
policySettings 最高优先级,不可被覆盖
7
配置变更安全
危险配置变更(含远程推送)须用户再确认
8
规则防篡改
沙箱内禁止写入 settings.json
9
宽松保存
规则持久化用宽松解析,保护已有配置
10
非阻塞体验
分类器异步运行,不延迟对话框弹出
5.18 核心文件速查表
文件
职责
src/types/permissions.ts
所有类型定义:模式、规则、决策、分类器
src/utils/permissions/permissions.ts
权限决策核心逻辑
src/utils/permissions/permissionsLoader.ts
规则加载与持久化
src/utils/permissions/permissionRuleParser.ts
规则字符串解析/序列化
src/utils/permissions/permissionSetup.ts
权限上下文构建,危险规则检测
src/utils/permissions/permissionExplainer.ts
AI 风险说明生成
src/utils/permissions/dangerousPatterns.ts
危险解释器黑名单
src/utils/permissions/yoloClassifier.ts
Auto Mode AI 分类器
src/utils/sandbox/sandbox-adapter.ts
OS 沙箱集成层
src/services/remoteManagedSettings/securityCheck.tsx
远程管控安全检查
src/components/permissions/
所有权限 UI 组件
src/utils/swarm/permissionSync.ts
多 Agent 权限同步