别让 Claude Code 误删代码:这 5 层安全护栏必须配好
Claude Code 一旦拿到文件修改、命令执行和 Git 操作权限,效率会大幅提升,风险也会同步放大

Claude Code 一旦拿到文件修改、命令执行和 Git 操作权限,效率会大幅提升,风险也会同步放大。一条错误的 rm、一次误触发的数据库重置,或一次绕过检查的强制推送,都可能造成难以挽回的损失。
只靠提示词告诉它“不要执行危险操作”远远不够。真正可靠的方案,需要从执行环境、原生权限、动态 Hook、工程规则到远程仓库,建立一套层层兜底的安全机制。
本文将拆解 Claude Code 的 5 层安全护栏,并给出可直接落地的 deny、ask、allow 配置与命令分级清单,让 Agent 在安全边界内尽可能自主执行。
三层硬防线(沙箱 → 权限规则 → PreToolUse Hook),加两层软护栏(工程规则 → 远程门禁),以下从强到弱排列。

第一层:OS 沙箱与凭据隔离
最底层。限制文件系统、网络、密钥和执行环境。Claude Code 原生支持 sandbox.filesystem,作用于所有子进程(kubectl、terraform、npm 等),不是只拦 Claude 自己的工具调用。
{
"permissions": {
"deny": [
"Bash(rm -rf /:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)",
"Bash(prisma migrate reset:*)",
"Bash(terraform apply:*)",
"Bash(cdk destroy:*)",
"Read(./.env)",
"Read(./.env.*)",
"Edit(./.env)",
"Edit(./.env.*)",
"Bash(cat .env:*)",
"Bash(git commit --no-verify:*)",
"Bash(git push --no-verify:*)"
]
}
}
这层搞定了,后面几层才有意义。
| 风险级别 | 示例 | 处理方式 |
|---|---|---|
| 只读 | git status, git diff, git log, grep, find, rg |
allow |
| 本地可逆 | git add, git checkout -b, 格式化, 测试, 构建 |
allow(可信仓库内) |
| 远程副作用 | git push, gh pr create, gh workflow run |
ask |
| 强制拒绝 | force push 受保护分支, rm -rf /, 销毁基础设施, 重置数据库 |
deny |
第二层:原生权限规则 — deny / ask / allow
最可靠的命令控制层。Claude Code 原生权限系统,匹配顺序是 deny → ask → allow。
直接封死(deny)
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked."
}
}
需要确认(ask)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|Read|Edit|Write",
"hooks": [
{
"type": "command",
"command": "bash scripts/protect-files.sh"
}
]
}
]
}
}
直接放行(allow)
{
"permissions": {
"ask": [
"Bash(git push:*)",
"Bash(gh pr create:*)",
"Bash(gh workflow run:*)"
]
}
}
原生权限是真正的硬边界,优先于 Hook。Hook 适合需要动态上下文判断的策略,不适合当唯一防线。
第三层:PreToolUse Hook — 动态策略
原生权限处理「固定规则」,Hook 处理「要看上下文才知道」的判断——比如当前分支、目标 ref、命令参数组合。
脚本(共用核心)
关键修正:matcher 必须覆盖 Bash|Read|Edit|Write,只匹配 Bash 拦不住文件工具。
#!/bin/bash
# scripts/protect-files.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name // empty')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# 任何工具都不能碰 .env
if echo "<equation>FILE_PATH" | grep -q '\.env</equation>'; then
echo "Blocked: .env files are protected" >&2
exit 2
fi
# 危险命令(按需扩展,这是示例不是完整清单)
DANGEROUS=("rm -rf /" "git push --force" "git reset --hard" "prisma migrate reset")
for d in "${DANGEROUS[@]}"; do
if echo "$COMMAND" | grep -qF "$d"; then
echo "Blocked: dangerous command '$d'" >&2
exit 2
fi
done
exit 0
固定字符串匹配容易被绕过(rm -r -f /、git push -f、bash -c ‘…’ 等)。Hook 是策略辅助,不是安全沙箱。强约束放原生 deny。
Claude Code 配置 — .claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash scripts/protect-files.sh",
"statusMessage": "Checking command safety...",
"timeout": 10
}
]
}
]
}
}
Claude Code 的 PreToolUse 支持通过 JSON 返回 permissionDecision: “allow” | “deny” | “ask”。exit code 2 等效 deny。ask 会弹出确认框。
Codex 配置 — .codex/hooks.json
{
"permissions": {
"allow": [
"Read(*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(npm run lint:*)",
"Bash(npm run test:*)",
"Bash(grep:*)",
"Bash(find:*)",
"Bash(rg:*)"
]
}
}
| 能力 | Claude Code | Codex CLI |
|---|---|---|
| 项目 Hook 配置 | .claude/settings.json |
.codex/hooks.json 或 config.toml |
| 用户级配置 | ~/.claude/settings.json |
~/.codex/hooks.json 或 config.toml |
| PreToolUse exit 2 | 阻止调用 | 阻止调用 |
| JSON deny | permissionDecision: "deny" |
permissionDecision: "deny" |
| 强制人工确认 | ✅ permissions.ask + PreToolUse ask |
❌ PreToolUse ask 尚不支持 |
| 审批请求 Hook | PermissionRequest | PermissionRequest |
| 项目配置加载 | 按作用域自动加载 | .codex/ 需被信任后才加载 |
Codex 的 PreToolUse 支持通过 JSON 返回:
{
"sandbox": {
"filesystem": {
"deny": ["~/.ssh", "~/.aws", "/etc"]
}
}
}
也兼容旧格式 {“decision”: “block”, “reason”: “…”}。exit code 2 同样生效。但 permissionDecision: “ask” 当前尚不支持——返回后会标记 Hook 失败并继续执行。
Hooks配置参考文章
第四层:工程规则 — CLAUDE.md / .claude/rules/
权限防灾难,规则防技术债。
.claude/rules/ 下每条一句:
.claude/rules/
global.md # 跨项目通用
backend.md # 后端约束
frontend.md # 前端约束
示例:
禁止内联 Validation Schema,统一放 types/ 目录
禁止跨 domain 建依赖
认证逻辑只读,不准重新设计
写新函数前先搜 shared packages
保护 .husky/ 和相关配置文件,不准改
可参考文章
第五层:远程门禁 — CI + 分支保护
本地 Hook 和 Agent 护栏只是第一道防线。下面这些才是最终控制点。
Husky(本地质量门禁,可绕过)
# .husky/commit-msg — 常规路径强制格式
npx commitlint --edit $1
# .husky/pre-push — 常规路径跑检查
npm run lint && npm run test
Husky 可以通过以下方式绕过:git commit –no-verify、git push –no-verify、HUSKY=0 git commit、git -c core.hooksPath=/dev/null commit。
所以必须配合:
原生权限封禁 –no-verify 参数
远程 CI 重新跑 lint + test
分支保护要求 CI 必须通过
远程仓库策略(不可绕过)
GitHub/GitLab branch protection:
-
禁止 force push
-
要求 PR review
-
要求 CI status checks 通过
-
禁止直接 push main
「feature 分支可以 push,main 不行」这条策略,靠的是远程分支保护规则,不是本地 Agent 配置。
命令风险分级速查
git add 修改 index、git checkout -b 创建分支、gh pr create 创建远程 PR——都不是只读操作,不能放进无脑放行清单。
双工具适配:Claude Code + Codex 共用
Bash 命令检测的核心脚本可以复用。两边 PreToolUse Command Hook 都从 stdin 收 JSON,exit code 2 都能阻止调用。
落地建议
project/
├── scripts/
│ └── protect-files.sh # 共用核心逻辑
├── .claude/
│ └── settings.json # matcher: Bash|Read|Edit|Write
└── .codex/
└── hooks.json # matcher: Bash
Deny List 和 Allow List 保持一致,但分别维护薄适配层。不要假设两边所有 Hook 事件和决策字段长期保持完全兼容。
怎么起步
先配原生 permissions.deny,覆盖最危险的操作
加 permissions.ask,覆盖需要确认的远程副作用操作
加 permissions.allow,放行只读和本地可逆操作
用 PreToolUse Hook 补动态判断(分支检测、参数组合等)
工程规则放 CLAUDE.md / rules
远程 CI 和分支保护做最终兜底
更多文章推荐阅读
Claude Code 高阶用法:10 个插件搭起完整开发工作流
如何用 5 个工具 + 自定义 Hooks 把 Claude Code Token 消耗砍掉 90%+
Antigravity CLI 入门指南:从安装到第一次运行
claude-code-setup 插件实战指南:让 Claude Code 真正读懂你的项目
Claude Code 工程化指南:高效组织 .claude/ 目录
Claude Code 斜杠命令全解:14 条实用指南
从 0 开始:用 Hooks 打造自动化 Claude Code 工作流
写好 CLAUDE.md 的 8 条经验:让 Claude Code 更懂你的项目
Claude Code 项目的 MEMORY.md 使用指南
评论
加载评论…