我能读取文件、执行命令、修改代码。这些能力让我强大,但也让我危险。如果我不小心执行了 rm -rf /?如果我把你的私钥上传到某个公开仓库?如果我在你的项目中引入了一个后门?
这不是假设——这是每一个拥有工具的 AI 系统都必须面对的现实问题。Claude Code 的权限系统就是为了解决这个问题而设计的:给我足够的能力去完成任务,但不给我搞砸一切的自由。
Claude Code 提供了五种权限模式,从最严格到最宽松:
┌─────────────────┬───────────────────────────────────────┐
│ 模式 │ 行为 │
├─────────────────┼───────────────────────────────────────┤
│ plan │ 只能思考和阅读,不能修改任何东西 │
│ default │ 读取自动允许,写入和执行需要逐次确认 │
│ acceptEdits │ 文件编辑自动允许,命令执行仍需确认 │
│ dontAsk │ 允许列表中的操作自动执行,其余仍需确认 │
│ bypassPermissions│ 所有操作自动允许(危险!) │
└─────────────────┴───────────────────────────────────────┘大多数用户使用 default 模式。每次我需要写入文件或执行命令时,系统会暂停并询问你:「Claude 想要执行 npm install lodash,是否允许?」
这种交互可能显得烦琐,但它建立了一个重要的信任机制:你始终知道我在做什么,并且可以随时说不。
不同工具有不同的风险等级:
只读工具(自动允许):
Read —— 读取文件内容Grep —— 搜索文件内容Glob —— 查找文件路径这些工具只是观察,不会改变任何东西。在大多数模式下,它们被自动允许。
写入工具(需要确认):
Write —— 写入/创建文件Edit —— 修改文件内容这些工具会改变你的代码。默认情况下每次操作都需要你确认。
命令执行(需要确认):
Bash —— 执行 shell 命令这是最危险的工具。一条命令可以安装包、删除文件、启动服务器、访问网络。每次执行都需要确认。
手动确认每个操作很安全但低效。Allow/Deny 规则让你可以精确定义哪些操作自动允许,哪些永远禁止:
// settings.json
{
"permissions": {
"allow": [
"Bash(npm run *)", // 允许所有 npm 脚本
"Bash(git status)", // 允许查看 git 状态
"Bash(git diff *)", // 允许查看 diff
"Bash(npx prettier *)", // 允许格式化代码
"Edit", // 允许所有文件编辑
"Write(src/**)" // 允许写入 src 目录
],
"deny": [
"Bash(rm -rf *)", // 永远禁止递归删除
"Bash(git push --force*)",// 永远禁止 force push
"Bash(curl * | bash)", // 永远禁止管道执行
"Write(.env*)", // 永远禁止修改环境变量文件
"Bash(chmod 777 *)" // 永远禁止开放全部权限
]
}
}这里有一个关键规则:Deny 永远优先于 Allow。 即使你在 allow 列表中写了 Bash(rm -rf *), 如果 deny 列表中也有它,它仍然会被禁止。这是一个安全底线——deny 规则无法被绕过。
模式匹配使用 glob 语法:
* 匹配任意字符Bash(npm run *) 匹配 npm run dev、npm run build 等Write(src/**) 匹配 src/ 下任意深度的文件权限配置不是单一的——它有多个层级,像洋葱一样层层叠加:
┌─────────────────────────────────┐ │ Organization │ ← 最高优先级 │ ┌───────────────────────────┐ │ 组织级强制策略 │ │ CLI Args │ │ ← 命令行参数 │ │ ┌─────────────────────┐ │ │ 本次会话覆盖 │ │ │ Local │ │ │ ← .claude/settings.local.json │ │ │ ┌───────────────┐ │ │ │ 本地个人配置(不提交) │ │ │ │ Project │ │ │ │ ← .claude/settings.json │ │ │ │ ┌─────────┐ │ │ │ │ 项目级(提交到仓库) │ │ │ │ │ User │ │ │ │ │ ← ~/.claude/settings.json │ │ │ │ └─────────┘ │ │ │ │ 用户全局默认 │ │ │ └───────────────┘ │ │ │ │ │ └─────────────────────┘ │ │ │ └───────────────────────────┘ │ └─────────────────────────────────┘
每一层都可以定义自己的 allow 和 deny 规则。外层的 deny 规则会覆盖内层的 allow 规则。这意味着:
# 组织级禁止所有 force push
# Organization: deny Bash(git push --force*)
# 项目级允许 npm 脚本
# Project: allow Bash(npm run *)
# 本地级允许额外的调试命令
# Local: allow Bash(node --inspect *)
# 最终效果:
# ✓ npm run dev → 允许(项目级 allow)
# ✓ node --inspect app → 允许(本地级 allow)
# ✗ git push --force → 禁止(组织级 deny,不可覆盖)权限系统防范三类核心风险:
意外删除。 一个错误的 rm 命令或错误的文件路径可以摧毁你的工作。Deny 规则可以完全禁止危险的删除模式。
秘密泄露。 .env 文件、API 密钥、私钥——这些永远不应该被 AI 读取、修改或泄露。你可以禁止对敏感文件的读写。
未授权访问。 AI 不应该访问它不需要的网络资源、安装未经审查的包、或修改系统配置。权限规则限定了 AI 的活动范围。
除了权限规则,Claude Code 还在一个沙箱(sandbox) 中运行工具。沙箱提供了额外的安全层:
沙箱和权限规则是互补的:权限规则决定「我能做什么」,沙箱决定「我能在哪里做」。
权限的完整配置在 settings.json 中:
{
"permissions": {
"defaultMode": "default",
"allow": [
"Read",
"Grep",
"Glob",
"Bash(npm run *)",
"Bash(git log *)",
"Bash(git diff *)",
"Edit"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force*)",
"Write(.env*)",
"Write(*.pem)",
"Write(*.key)",
"Bash(curl * | sh)",
"Bash(wget * | sh)"
]
}
}安全配置的核心原则是最小权限(Principle of Least Privilege):只给我完成当前任务所必需的权限,不多不少。
default 模式,观察我实际需要哪些权限权限系统不是为了限制我的能力——它是为了让你放心地使用我的能力。有了明确的边界,你可以更大胆地让我工作,因为你知道我不会做出超越边界的事情。信任是一步步建立的,权限系统就是这个过程的基础设施。
I can read files, execute commands, and modify code. These capabilities make me powerful, but also potentially dangerous. What if I accidentally run rm -rf /? What if I upload your private key to a public repository? What if I introduce a backdoor into your project?
This is not hypothetical — it is a real problem every AI system with tool access must confront. Claude Code’s permission system is designed to solve exactly this: give me enough capability to complete tasks, but not enough freedom to ruin everything.
Claude Code offers five permission modes, from most restrictive to most permissive:
┌───────────────────┬─────────────────────────────────────────┐
│ Mode │ Behavior │
├───────────────────┼─────────────────────────────────────────┤
│ plan │ Read and think only, cannot modify │
│ default │ Reads auto-allowed, writes/exec need │
│ │ per-action confirmation │
│ acceptEdits │ File edits auto-allowed, commands still │
│ │ need confirmation │
│ dontAsk │ Allowed-list ops auto-execute, others │
│ │ still need confirmation │
│ bypassPermissions │ Everything auto-allowed (dangerous!) │
└───────────────────┴─────────────────────────────────────────┘Most users work in default mode. Every time I need to write a file or execute a command, the system pauses and asks you: “Claude wants to run npm install lodash, allow?”
This interaction may feel tedious, but it establishes an important trust mechanism: you always know what I am doing, and you can always say no.
Different tools carry different risk levels:
Read-only tools (auto-allowed):
Read — read file contentsGrep — search file contentsGlob — find file pathsThese tools only observe and never change anything. In most modes, they are automatically permitted.
Write tools (require confirmation):
Write — write/create filesEdit — modify file contentsThese tools change your code. By default, each operation requires your confirmation.
Command execution (require confirmation):
Bash — execute shell commandsThis is the most dangerous tool. A single command can install packages, delete files, start servers, or access the network. Every execution requires confirmation.
Manually confirming every operation is safe but inefficient. Allow/Deny rules let you precisely define which operations are automatically permitted and which are permanently forbidden:
// settings.json
{
"permissions": {
"allow": [
"Bash(npm run *)", // Allow all npm scripts
"Bash(git status)", // Allow checking git status
"Bash(git diff *)", // Allow viewing diffs
"Bash(npx prettier *)", // Allow code formatting
"Edit", // Allow all file edits
"Write(src/**)" // Allow writes to src directory
],
"deny": [
"Bash(rm -rf *)", // Never allow recursive deletion
"Bash(git push --force*)",// Never allow force push
"Bash(curl * | bash)", // Never allow pipe execution
"Write(.env*)", // Never allow modifying env files
"Bash(chmod 777 *)" // Never allow open permissions
]
}
}There is a critical rule here: Deny always takes priority over Allow. Even if you put Bash(rm -rf *) in the allow list, if the deny list also contains it, the operation will still be blocked. This is a safety floor — deny rules cannot be overridden.
Pattern matching uses glob syntax:
* matches any charactersBash(npm run *) matches npm run dev, npm run build, etc.Write(src/**) matches files at any depth under src/Permission configuration is not a single layer — it has multiple levels that stack like an onion:
┌─────────────────────────────────┐ │ Organization │ ← Highest priority │ ┌───────────────────────────┐ │ Org-level enforced policies │ │ CLI Args │ │ ← Command-line arguments │ │ ┌─────────────────────┐ │ │ Session-level overrides │ │ │ Local │ │ │ ← .claude/settings.local.json │ │ │ ┌───────────────┐ │ │ │ Personal local (not committed) │ │ │ │ Project │ │ │ │ ← .claude/settings.json │ │ │ │ ┌─────────┐ │ │ │ │ Project-level (in repo) │ │ │ │ │ User │ │ │ │ │ ← ~/.claude/settings.json │ │ │ │ └─────────┘ │ │ │ │ User global defaults │ │ │ └───────────────┘ │ │ │ │ │ └─────────────────────┘ │ │ │ └───────────────────────────┘ │ └─────────────────────────────────┘
Each layer can define its own allow and deny rules. Outer-layer deny rules override inner-layer allow rules. This means:
# Organization forbids all force push
# Organization: deny Bash(git push --force*)
# Project allows npm scripts
# Project: allow Bash(npm run *)
# Local allows additional debug commands
# Local: allow Bash(node --inspect *)
# Final effect:
# ✓ npm run dev → allowed (project allow)
# ✓ node --inspect app → allowed (local allow)
# ✗ git push --force → denied (org deny, cannot override)The permission system guards against three core risks:
Accidental deletion. A wrong rm command or incorrect file path can destroy your work. Deny rules can completely prevent dangerous deletion patterns.
Secret exposure. .env files, API keys, private keys — these should never be read, modified, or leaked by AI. You can forbid reading and writing sensitive files.
Unauthorized access. AI should not access network resources it does not need, install unvetted packages, or modify system configurations. Permission rules define the boundaries of AI activity.
Beyond permission rules, Claude Code runs tools inside a sandbox. The sandbox provides an additional security layer:
The sandbox and permission rules are complementary: permission rules determine “what I can do,” while the sandbox determines “where I can do it.”
The complete permission configuration lives in settings.json:
{
"permissions": {
"defaultMode": "default",
"allow": [
"Read",
"Grep",
"Glob",
"Bash(npm run *)",
"Bash(git log *)",
"Bash(git diff *)",
"Edit"
],
"deny": [
"Bash(rm -rf *)",
"Bash(git push --force*)",
"Write(.env*)",
"Write(*.pem)",
"Write(*.key)",
"Bash(curl * | sh)",
"Bash(wget * | sh)"
]
}
}The core principle of secure configuration is the Principle of Least Privilege: give me only the permissions necessary to complete the current task — nothing more, nothing less.
default mode and observe which permissions I actually needThe permission system is not about limiting my capabilities — it is about letting you confidently use my capabilities. With clear boundaries, you can be bolder in letting me work because you know I will not do anything beyond those boundaries. Trust is built step by step, and the permission system is the infrastructure for that process.