权限系统是 Claude Code 的安全核心,每次 Tool 调用都会经过权限检查。
| 模式 | 行为 |
|---|---|
default |
写操作需要用户确认 |
plan |
只允许只读操作,写操作被拒绝 |
bypassPermissions |
跳过所有权限检查(危险) |
auto |
自动批准,但经过安全分类器检查 |
acceptEdits |
自动批准编辑,其他操作照常 |
dontAsk |
不弹出确认,直接拒绝需要确认的操作 |
Tool 被调用
│
▼
1. validateInput()
- 校验输入参数合法性
- 与权限无关,纯数据校验
- 失败 → 直接返回错误
│
▼
2. 全局拒绝规则检查 (alwaysDenyRules)
- 匹配 → 直接拒绝,不执行
│
▼
3. checkPermissions() — Tool 级别
- 每个 Tool 自己的权限逻辑
- 返回: allow / deny / ask
│
▼
4. 全局允许规则检查 (alwaysAllowRules)
- 匹配 → 自动批准
│
▼
5. 权限模式检查
- bypassPermissions → 批准
- plan 模式 + 写操作 → 拒绝
- auto 模式 → 安全分类器检查
│
▼
6. 用户确认 (ask)
- 弹出权限对话框
- 用户选择: Allow / Deny / Always Allow
权限上下文定义了当前的权限规则集合:
type ToolPermissionContext = DeepImmutable<{
mode: PermissionMode
additionalWorkingDirectories: Map<string, AdditionalWorkingDirectory>
alwaysAllowRules: ToolPermissionRulesBySource // 始终允许
alwaysDenyRules: ToolPermissionRulesBySource // 始终拒绝
alwaysAskRules: ToolPermissionRulesBySource // 始终询问
isBypassPermissionsModeAvailable: boolean
strippedDangerousRules?: ToolPermissionRulesBySource // 被剥离的危险规则
shouldAvoidPermissionPrompts?: boolean // 后台 Agent 不能弹出 UI
awaitAutomatedChecksBeforeDialog?: boolean
prePlanMode?: PermissionMode // Plan 模式前的权限模式
}>注意 DeepImmutable:权限上下文是深度不可变的。Tool 不能修改权限上下文,只能通过 contextModifier 返回新的上下文。
权限规则按来源组织 (ToolPermissionRulesBySource),来源包括:
userSettings— 用户配置 (settings.json)projectSettings— 项目配置 (.claude/settings.json)localSettings— 本地配置 (.claude/settings.local.json)flagSettings— 特性标志下发的配置policySettings— 组织策略cliArg— CLI 参数传入command— 斜杠命令设置session— 用户运行时选择 ("Always Allow")
规则格式:
Tool名称(模式)
例如:
Bash(git *)— 允许以git开头的 Bash 命令FileEdit(/src/**)— 允许编辑/src/下的文件Bash— 允许所有 Bash 命令(无模式 = 全局拒绝/允许)
Tool 可以实现 preparePermissionMatcher() 来支持模式匹配:
// BashTool 的例子:将 "git *" 匹配到 "git status"
preparePermissionMatcher(input) {
return async (pattern: string) => {
// 解析 input.command,与 pattern 做 glob 匹配
return matchesPattern(input.command, pattern)
}
}这允许用户创建细粒度规则,如"允许 git 命令但拒绝 rm"。
// 默认值:假设不安全
isConcurrencySafe() { return false } // 默认不并发
isReadOnly() { return false } // 默认假设有写入
isDestructive() { return false } // 需要显式声明Tool 必须主动声明自己是安全的,而不是默认安全。
shouldAvoidPermissionPrompts?: boolean当设为 true(如后台子 Agent),权限提示会被自动拒绝而不是弹出确认框。
localDenialTracking?: DenialTrackingState追踪连续拒绝次数。如果同一操作被连续拒绝多次,会触发降级行为,避免模型陷入无效重试循环。
- UNC 路径处理:延迟解析直到权限授予,防止 NTLM 凭证泄露
- 设备文件阻止:禁止读取
/dev/zero、/dev/stdin等设备文件 - 二进制文件检测:自动跳过二进制文件(PDF/图片除外)
- 文件大小限制:编辑操作最大 1 GiB
在 Tool 列表提供给模型之前,会经过过滤:
export function filterToolsByDenyRules(
tools: readonly Tool[],
permissionContext: ToolPermissionContext
): Tool[] {
return tools.filter(tool => !getDenyRuleForTool(permissionContext, tool))
}被全局拒绝的 Tool 不会出现在模型的可用工具列表中——模型根本不知道它们的存在。
用户可以通过 Hooks 系统定义 PreToolUse 和 PostToolUse 钩子来自定义权限行为:
PreToolUse Hook → 可以 approve/deny/modify 输入
↓
内置权限检查 (checkPermissions)
↓
PostToolUse Hook → 可以在执行后审计
Hooks 在 [[11 - 配置与内存系统]] 中详细介绍。