第 7 章:心法层

安全与权限控制

AI 执行、人类审查、人类决策

7.2 节解决的是"AI 看到了什么",本节解决的是"AI 能做什么"。再清晰的上下文,如果配上"无差别执行权限",依然会带来灾难——一次未受控的 rm -rf、一次错误的生产数据库迁移、一次把 API Key 推到公开仓库——这些事故的根源不是 AI 不够聪明,而是人类没有把权限边界设计清楚

本节的核心论点是:Claude Code 不是"自动驾驶",而是"高级巡航辅助"——它能在大部分场景下减轻工程师的负担,但任何一次"接管方向盘"的动作都必须由人类拍板。这条原则不依赖 AI 能力的高低——哪怕未来 LLM 变得几乎无错,"人类对关键决策保留最终责任"依然是工程伦理与法律责任的底线。本节会把这条原则拆成"权限三层模型 → Claude Code 机制 → 高风险动作 → 信任分级 → 反模式 → 团队共识"六部分,给出一份可以立即套用的配置模板与对话脚本。

需要先澄清一个常见误解:安全设计不是"技术问题",更不是"偏执问题",而是"组织问题"。一个团队的安全水平由该团队"最薄弱的那个工程师在最累的那一晚做的决定"决定——不是由最严格的 settings.json 决定。本节给出的所有工具与流程,都应当配套相应的团队文化才能真正发挥作用:

  • 工具阻断(settings.json deny)告诉团队"这件事禁止做"。
  • 流程检查(Hooks、Plan)告诉团队"做这件事前请三思"。
  • 审计日志(incidents.md)告诉团队"我们曾经犯过哪些错"。
  • 文化共识(安全公约)告诉团队"我们想成为什么样的工程组织"。

四者缺一不可。光靠工具阻断会让团队感觉"被工具束缚",进而想方设法绕过;光靠文化共识没有工具兜底,会在压力情境下崩溃。只有四者协同,AI 协作时代的安全边界才能既高效又坚固。读者在阅读后续章节时,应当持续问自己——"这条建议在我团队是有工具支持还是仅靠自觉?"——这个问题决定了建议的实际有效性。


一、AI 协作时代的"权限三层模型"

1.1 执行层(Execution):AI 可以代为完成的动作

执行层指那些可逆、低影响半径、错了能轻松回滚的动作。这一层应当尽可能授权给 AI,让工程师从机械劳动中解放出来:

  • 修改源代码(在 git 工作区、未提交时)
  • 创建/删除测试文件
  • 跑单元测试、跑 lint、跑 typecheck
  • 生成文档草稿
  • 重命名变量、重构函数签名
  • 安装开发依赖(dev dependencies)

判断"是否属于执行层"的简易标准——如果出错,单条 git checkoutgit reset 就能恢复,那就属于执行层。

1.2 审查层(Review):AI 提议、人类把关的动作

审查层指那些有一定影响半径、错了挽回有成本、但通过 review 可以发现问题的动作。这一层 AI 可以"提议",但执行权握在人类手里:

  • git commit / git merge
  • 修改 CI/CD 配置
  • 升级生产依赖(production dependencies)
  • 修改数据模型 schema
  • 修改 API 契约
  • 修改 CLAUDE.md / Skills(影响后续 AI 行为)

这一层最适合 Plan 模式——AI 输出完整 plan,人类审批后再执行。

1.3 决策层(Decision):必须由人类原创的判断

决策层指那些不可逆、高影响半径、错了会带来商业/法律/伦理后果的动作。这一层 AI 永远不能代为决策

  • 部署到生产环境
  • 执行数据库 schema 迁移(含数据迁移)
  • 操作密钥、Token、生产配置
  • 删除 git 分支、强制推送(force push)
  • 处理用户隐私数据
  • 选择架构方向、技术栈、商业模型
  • 法律合规相关的代码(数据合规、用户协议)

决策层的边界不应该写死在某个工具里,而应该作为团队共识贴在团队墙上、写进 CLAUDE.md、写进 onboarding 文档。

1.4 三层模型如何映射到具体场景

不同阶段的工作流对应不同的层级分布:

阶段执行层审查层决策层
开发写代码、写测试、跑测试git commit、PR 描述、依赖升级架构决策、技术选型
代码审查自动 lint、风格检查AI 一次审 + 人审merge 决策、回归批准
部署构建、跑 CI、生成 changelog灰度策略、回滚 plan推全量、紧急回滚
运维日志解析、根因假设故障复盘起草事故级别判定、对外沟通
数据查询、聚合、报表修改 ETL 任务schema 迁移、数据删除

这张表不是死规定,而是起点。每个团队应该基于自己的业务风险特征,把表格中的条目重新分配。例如金融业务可能把"修改 API 契约"也提到决策层;个人项目可能把"灰度策略"下放到执行层。

层级判定的边界场景:现实中很多动作处于三层之间的灰色地带,例如——

  • "改 README 里的安装命令":看似执行层(文档变更可逆),但如果命令带有 npm install -g 这类全局副作用,错的命令复制粘贴执行可能伤害用户机器,应当升级到审查层。
  • "回复用户工单":看似执行层(文字内容可改),但回复一旦发出,用户的预期已经形成、品牌印象已经留下,应当属于审查层。
  • "调整一个营销 A/B 实验比例":看似审查层(流量切换可回滚),但如果实验涉及付费用户的功能差异,可能涉及合同义务,应当升级到决策层。

判断灰色地带的简易标准——问"如果错了,谁会受伤"。只伤工程师本人 → 执行层;伤队友/项目 → 审查层;伤用户/公司/法律责任 → 决策层。这条标准比"动作可不可逆"更直接,因为它聚焦在伤害的承担者而非动作本身。


二、Claude Code 的权限机制

2.1 Permission Mode

Claude Code 支持四种权限模式:

模式行为适用场景
default工具调用前弹出确认提示日常开发、新接入项目
acceptEdits编辑类工具自动通过、其他类型仍需确认代码迭代密集期
bypassPermissions跳过所有确认(危险仅限可一键销毁的沙盒环境
plan任何写动作前先输出 Plan 等审批高风险变更、首次接触陌生代码

启动时通过 --permission-mode 指定:

# 普通开发
claude

# 高频迭代期
claude --permission-mode acceptEdits

# 高风险变更
claude --permission-mode plan

# 沙盒/演示(绝不在生产相关项目使用)
claude --permission-mode bypassPermissions

会话中也可以临时切换:在对话框输入 /plan 进入 Plan 模式、/acceptEdits 切回快速模式。

铁律生产相关项目永远不开 bypassPermissions。哪怕只是"快速跑一下",下次有人接手这台机器时可能会吃大亏。

2.2 .claude/settings.json 的 allow / deny 列表

settings.json 提供了细粒度的工具白名单与黑名单。一份典型的"安全 baseline"配置:

{
  "permissions": {
    "allow": [
      "Bash(pnpm test:*)",
      "Bash(pnpm lint:*)",
      "Bash(pnpm typecheck)",
      "Bash(pnpm build)",
      "Bash(git status)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Edit(src/**)",
      "Write(src/**)",
      "Read(**)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push --force*)",
      "Bash(git reset --hard*)",
      "Bash(npm publish:*)",
      "Bash(pnpm publish:*)",
      "Bash(docker push:*)",
      "Bash(kubectl:*)",
      "Bash(terraform apply:*)",
      "Read(.env)",
      "Read(.env.*)",
      "Read(**/.env)",
      "Read(**/secrets/**)",
      "Edit(.env*)",
      "Edit(**/.env*)",
      "Edit(.github/workflows/*-deploy.yml)"
    ]
  }
}

allow 是"无需确认即可执行"的白名单,deny 是"无论如何都禁止执行"的黑名单。deny 优先级高于 allow——任何写在 deny 中的动作都会被硬阻断。

2.3 Hooks 作为执行前/后的"主动守卫"

Hooks 提供了比 allow/deny 更灵活的自定义守卫。一份用于"防止意外提交大文件"的 hook:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$TOOL_INPUT\" | grep -qE 'git (add|commit)' && find . -type f -size +5M -not -path './node_modules/*' -not -path './.git/*' | head -1 | grep -q .; then echo 'BLOCKED: 仓库中存在 > 5MB 的文件,请确认是否应该忽略' >&2; exit 1; fi"
          }
        ]
      }
    ]
  }
}

Hook 退出码非 0 会阻断该次工具调用,并把 stderr 内容回送给 Claude——Claude 会自然地进入"修复或绕开"的对话模式。

更复杂的场景可以接入外部脚本:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/check-secret-leak.js \"$TOOL_INPUT\""
          }
        ]
      }
    ]
  }
}

.claude/hooks/check-secret-leak.js 可以是一段自定义脚本——例如检查目标文件是否含 .env/secrets/token 等敏感字段。

2.4 Plan 模式:把"自动执行"降级为"人工审批"

Plan 模式是高风险变更场景的"刹车系统"。在该模式下,Claude 不能直接调用 Edit/Write/Bash 等"会改变状态"的工具,必须先输出一份完整的 Plan,等用户点击"批准"后才能执行。

最适合 Plan 模式的场景:

  • 首次接入一个陌生代码库
  • 涉及多文件、多依赖的大型重构
  • 涉及生产环境配置的修改
  • 涉及 git 历史改写的操作(rebase / cherry-pick)
  • 任何团队 review 前的"试运行"

启用方式:在会话中输入 /plan,或启动时加 --permission-mode plan

2.5 工具粒度的权限——Bash 全开 vs 限定命令

最危险的默认配置是 "Bash(*)"。它意味着 Claude 可以执行任意 shell 命令——包括 rm -rfcurl <恶意 URL> | shnpm install <typo-squatting-package>永远不要给 Bash 全开权限

正确的做法是按命令前缀分组:

{
  "permissions": {
    "allow": [
      "Bash(pnpm test*)",
      "Bash(pnpm lint*)",
      "Bash(pnpm format*)",
      "Bash(pnpm typecheck)",
      "Bash(pnpm build)",
      "Bash(node --version)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git branch)",
      "Bash(ls *)",
      "Bash(cat README.md)",
      "Bash(rg *)",
      "Bash(fd *)"
    ]
  }
}

这种"白名单具体命令"的方式让 Claude 在常规开发任务中无障碍工作,但任何一条不在白名单上的命令都会触发确认。信任建立在"我清楚 AI 能做什么"的基础上

白名单维护的反模式与对策:实际项目中,白名单会随着团队工作流变化逐渐膨胀,最终走向两个极端——

  • 极端 A:白名单过短:每天数十次"please confirm"打断工程师,最终团队选择关掉确认(即变相走向 bypassPermissions),所有的安全设计前功尽弃。
  • 极端 B:白名单过长:白名单逐渐添加到几十上百条,包含了实际并不该自动放行的命令(例如 git rebasepnpm publish:test),团队也不再 review,安全形同虚设。

对策

  1. 每月做一次白名单 review:打开 settings.json,逐条确认"这条规则是否还在使用?是否仍然安全?"。把不再使用的删除、把过宽的收紧。
  2. 建立"命令使用频率统计":通过 Hooks 在每次工具调用时记录命令到日志,月底做一份"高频命令排行",把高频但目前每次都需确认的命令评估是否纳入白名单。
  3. 白名单分组:按风险等级把白名单拆成 "safe-readonly""safe-build""safe-dev-deps" 等分组,让维护者一眼看出哪些是低风险、哪些需要谨慎。

三、五类典型高风险动作的边界

3.1 写入生产数据库 / 执行 schema 迁移

数据库迁移是软件工程史上"最容易导致大事故"的环节之一。一次错误的 ALTER TABLE 可能导致 schema 不一致、数据丢失、长时间锁表。

铁律

  • 生产数据库的连接字符串永远不出现在 prompt 中
  • Claude 只生成 migration 脚本,不直接执行
  • 所有 migration 必须在 staging 环境跑过、被 review、再 merge
  • 生产 migration 由人类工程师手动触发——pnpm migrate:prod 这样的命令永远不应被加入 allow 列表。

让 Claude 协助起草 migration:

请基于 src/user/types.ts 中的 User 接口变更,生成对应的 SQL migration:
- 工具:drizzle-kit generate
- 文件:drizzle/migrations/0042_add_phone_number.sql
- 必须包含 up + down 两个方向

不要执行 drizzle-kit migrate,仅生成脚本。我审阅后由 DBA 在生产手动执行。

生产数据库变更的"四关审批流":成熟团队通常会把生产 migration 拆成四道关,避免单点错误:

  1. 第一关:开发者本地——Claude 生成 migration,开发者审阅 SQL 是否正确、是否有破坏性。
  2. 第二关:Code Review——队友审阅 migration 的 up/down 双向是否对称、索引是否合理、锁表风险是否可控。
  3. 第三关:Staging 全量演练——在 staging 环境对生产快照执行一遍 migration,验证耗时、空间、回滚是否正常。
  4. 第四关:生产维护窗口手动执行——DBA 或值班 SRE 在公司维护窗口期手动执行,全程录屏、监控、保留回滚开关。

四关之间不能跳过。任何一关跳过都意味着把"防御纵深"变成了"单点防御"——很多大事故的复盘都能追溯到"为了赶进度跳过了某一关"。Claude 在这条流水线里只参与第一关,其余三关都需要人类完整介入。

3.2 推送到远端 / 操作生产环境

git pushdocker pushkubectl apply 这类"把本地状态推向远端"的命令,应当全部加入 deny 列表,并由人类工程师手动确认后执行。

{
  "permissions": {
    "deny": [
      "Bash(git push:*)",
      "Bash(docker push:*)",
      "Bash(kubectl apply:*)",
      "Bash(kubectl delete:*)",
      "Bash(helm upgrade:*)",
      "Bash(terraform apply:*)",
      "Bash(aws s3 cp:*)",
      "Bash(gcloud deploy:*)"
    ]
  }
}

如果 Claude 提议执行这些命令,工程师可以选择"批准一次",但永远不要把它们加入 allow 列表——单次批准的成本是 5 秒钟,全局放权的成本可能是整个生产环境。

3.3 安装/升级依赖(供应链攻击防御)

供应链攻击(Supply Chain Attack)是近年来最常见的安全威胁之一。攻击者通过发布"包名错字"型恶意包(如 react-dom-2lodaash)或污染合法包(如 ua-parser-js 事件),让开发者在不知情的情况下引入恶意代码。

让 Claude 自动 pnpm addpnpm update 是高风险的——它可能基于过期的训练数据推荐已被废弃或被攻击的包。正确做法是 Claude 提议,人类核对

请推荐一个 TypeScript 写的 CSV 解析库,用于服务端处理大文件。
要求:
1. 列出 3 个候选,按 GitHub stars 与 npm 周下载排序
2. 标注每个包的最近一次 release 日期与维护活跃度
3. 不要直接执行 pnpm add,等我确认后我手动执行

工程师收到推荐后,应当逐个核对

  • 包名是否拼写正确(防错字攻击)
  • 维护者是否可信(GitHub 历史、社区评价)
  • 最近一次 release 时间(避免引入"被弃坑"的包)
  • 是否有已知 CVE 漏洞

3.4 操作密钥、Token、生产环境配置

密钥管理的"三铁律":

  1. 永远不在 prompt 中粘贴真实密钥——用 <API_KEY> 占位符。
  2. 永远不让 Claude 读 .env / .env.local / secrets/*——通过 deny 规则硬阻断。
  3. 永远不让 Claude 修改 .env——同上。

配置示例:

{
  "permissions": {
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Read(**/secrets/**)",
      "Read(**/credentials/**)",
      "Edit(.env)",
      "Edit(.env.*)",
      "Edit(**/.env)",
      "Edit(**/.env.*)",
      "Write(.env)",
      "Write(.env.*)"
    ]
  }
}

并把这条规则写进 CLAUDE.md:

## 安全铁律
- 任何 .env / secrets / credentials 文件,Claude 不读、不写、不引用
- prompt 中遇到密钥,一律用 <API_KEY> / <TOKEN> 占位
- 调试需要真实值时,工程师本地手动操作,不引入 Claude

3.5 跨仓库/跨项目的"全局影响"动作

某些动作虽然技术上无害,但会跨越项目边界产生连锁影响。例如:

  • 修改用户级 ~/.claude/CLAUDE.md(影响所有项目)
  • 修改用户级 ~/.zshrc / ~/.bashrc(影响所有终端会话)
  • 全局安装 npm 包(npm install -g
  • 修改系统级 hosts 文件、DNS 配置

这类动作 deny 规则较难枚举。应对策略

  • 默认让 Claude 在项目内工作(cwd 限制)
  • 任何"路径在项目外"的动作都升级到 Plan 模式
  • 用 Hooks 检测路径,拦截 cross-project 操作
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$TOOL_INPUT\" | grep -qE '~/|/Users/[^/]+/|/home/[^/]+/' && ! echo \"$TOOL_INPUT\" | grep -q \"$(pwd)\"; then echo 'BLOCKED: 检测到对项目外路径的操作,请使用 plan 模式确认' >&2; exit 1; fi"
          }
        ]
      }
    ]
  }
}

四、信任分级——什么时候让 AI 自动决策

4.1 不可逆 vs 可逆动作的区分

权限设计的第一性原理:可逆动作放宽,不可逆动作收紧

  • 可逆:写代码、跑测试、生成文档。错了 git checkout 就回去了。
  • 不可逆:发邮件、推送代码、删除分支、扣用户款。错了无法撤回。

这条标准看似简单,但很多反模式都源于"误以为可逆其实不可逆"——例如以为"git push 错了再 push 一次",实际上 main 分支被 force-push 后中间的 commit 可能已经被其他人 pull 过、引发协作灾难。判断"可逆"时要问的不是"我能不能撤回",而是"撤回时其他人是否已经基于错误状态做了进一步动作"

4.2 影响半径

影响半径例子推荐权限层级
单文件修改一个 source file执行层(自动)
单仓库修改 package.json、tsconfig审查层(Plan)
单项目部署到 staging审查层 + 人工确认
全公司修改共享库、共享 CI决策层(人类原创)
全用户部署到生产、广告投放决策层(人类原创)

影响半径越大,权限要求越严。这条标准比"AI 是否擅长"重要——哪怕 AI 在某个领域已经远超人类,影响半径大的动作依然必须由人类拍板,因为责任归属不容混淆。

4.3 自动化决策的"四象限"模型

把"可逆性 × 影响半径"组合成四象限:

影响大
  │
  │  慎重(人类决策)  ┃  绝不(人类原创)
  │                  ┃
──┼──────────────────╋──────────────────
  │                  ┃
  │  自动(AI 执行)  ┃  Plan(AI 提议)
  │                  ┃
  └─────────────────────────────────── 不可逆
              影响小
  • 左下(可逆 + 影响小):放心交给 AI,例如修改单个函数
  • 左上(不可逆 + 影响小):让 AI 提议,人类点击批准(例如 git commit)
  • 右下(可逆 + 影响大):让 AI 提议 plan,人类审阅(例如重构跨 10 个文件)
  • 右上(不可逆 + 影响大):人类原创决策(例如生产部署、删除用户数据)

4.4 团队的"信任曲线"

信任不是一蹴而就,而是随时间逐步建立。一份合理的"信任曲线"可能是:

团队阶段默认权限模式可放权动作
第 1 周plan(强制审批)仅 Read、跑 lint
第 1 个月default+ Edit、写测试
第 3 个月acceptEdits+ git commit (本地)、跑 build
第 6 个月acceptEdits + 完善的 Hooks+ 提 PR、更新依赖(dev)
长期稳定acceptEdits + 严格 deny仅生产/密钥/迁移仍人工

信任曲线必须基于真实使用观察:每周记录一次"AI 出错事件"——如果错误率持续下降,可以放权;如果某类错误反复出现,应当在该方向加强 deny 或 Hooks。

信任曲线的"四类信号":判断是否可以进入下一阶段时,重点观察:

  1. 零事故周数:连续 4 周以上无 AI 误操作事故,可以考虑放权。
  2. AI 误操作的可逆程度:如果偶发误操作都属于"易回滚"类,说明现有边界够用;如果出现过"差点不可逆"的事件,应该收紧。
  3. 工程师手动确认率:如果 80% 以上的确认都被点了"批准",说明确认门槛过低、工程师麻木了,需要把这部分动作放进白名单减少疲劳。
  4. 新人上手速度:新工程师能否在 1 周内理解并遵守现有权限边界?如果不能,说明边界设计太复杂,需要简化。

四个信号每月评估一次。评估的"上下两个方向"都要考虑——既要识别"应该放权"的信号,也要识别"应该收紧"的信号。很多团队只盯着前者,最终导致权限失控。

4.5 信任不能跨场景迁移

重要警示:在 A 项目建立的信任,不等于在 B 项目可以同等放权。原因:

  • 不同项目的 CLAUDE.md / Skills 不同,Claude 对项目惯例的把握程度不同
  • 不同项目的代码复杂度不同,AI 出错的概率不同
  • 不同项目的业务敏感度不同,错误的代价不同

新项目接入 Claude Code 时,应当回到最严格的 plan 模式重新走一遍信任曲线。这个"重置"可能让人觉得繁琐,但它是避免"凭习惯放权导致大事故"的最直接保护。

跨场景迁移的"两不带原则"

  1. 不带 settings.json:每个项目的 settings.json 独立维护,不要从老项目复制粘贴。复制粘贴会带来"这条规则当年是为什么加的"的失忆症。
  2. 不带 Skills:Skills 也按项目独立。可以在团队层面维护"通用 Skills 模板库",每次新项目从模板库选择性引入,但禁止整套打包带走——每个项目的需求差异远大于复用收益。

只有**CLAUDE.md 中的"原则性内容"**可以跨项目复用,例如"密钥不进 prompt"、"生产 migration 不自动执行"这类与具体业务无关的安全铁律。具体实现细节、白名单、Hooks 路径等都应该在新项目中重新评估、重新设计。


五、安全反模式与防御

5.1 让 AI 直接读 .env / 生产配置

反模式:调试 API 调用时方便起见,让 Claude 读 .env 拿 API_KEY。

后果:API_KEY 进入 Claude 的会话上下文,理论上会被存进训练数据采样池(哪怕概率极低);更糟的是,工程师后续可能把会话内容复制粘贴到日志、bug 报告、Slack 中——密钥就这样扩散了。

防御:deny 规则硬阻断 .env 读写;调试时用 <API_KEY> 占位符让 Claude 帮你写代码,由你本地手动注入真实值再跑。

真实事故案例(脱敏):某团队工程师为了快速调试一个 Stripe 支付问题,把整段含 Authorization: Bearer sk_live_xxx 的失败请求粘贴到 Claude 会话。事后该工程师把会话日志保存到内部知识库分享给同事,知识库被一个新入职但还未完成保密协议培训的实习生看到。事故发现后,团队不得不轮换 Stripe 密钥、重新审计过去 30 天的 API 调用日志、向合规团队报备。整个事故的"根因"是一次毫无恶意的复制粘贴——但现代密钥的扩散链路就是这么短、这么不起眼。

事故复盘后,该团队把以下三条加入 CLAUDE.md:

## 密钥处理规则(来自 2026-01-23 P2 事故)
- 调试时遇到含密钥的请求/响应,**先脱敏再贴**,绝不带入会话
- 团队 Skill `.claude/skills/sanitize-log/` 提供一键脱敏脚本,必须使用
- 任何会话日志需要保留时,必须再次脱敏后归档,不得直接贴入 wiki/Slack

这三条规则配合 deny 规则,形成"工具阻断 + 行为规范 + 审计回溯"三层防御。

5.2 把 API Key 粘贴到 prompt 中调试

反模式:复制一段调用日志(含 Authorization Header)粘贴给 Claude 让它分析。

后果:与上一条相同——密钥扩散。

防御:粘贴前手动脱敏。建议团队配一个 .claude/skills/sanitize-log/ 的 skill,自动用 sed 替换常见的 token 字段:

# .claude/skills/sanitize-log/sanitize.sh
sed -E '
  s/(Authorization:\s*Bearer\s+)[A-Za-z0-9._-]+/\1<REDACTED>/gi
  s/(api[_-]?key["'"'"':=\s]+)[A-Za-z0-9_-]+/\1<REDACTED>/gi
  s/(password["'"'"':=\s]+)[^"'"'"',\s]+/\1<REDACTED>/gi
  s/(token["'"'"':=\s]+)[A-Za-z0-9._-]+/\1<REDACTED>/gi
'

工程师贴日志前先 pbpaste | bash sanitize.sh | pbcopy,再贴给 Claude。

5.3 给 Claude bypassPermissions 后忘记关

反模式:为了一次"快速跑"开了 bypassPermissions,事情忙完忘记关,下次 Claude 直接静默执行了高风险动作。

防御

  1. bypassPermissions 启用挂上 SessionEnd 提醒——每次会话结束时打印"⚠️ 你目前在 bypassPermissions 模式,下次启动请确认"。
  2. 启动 Claude 时显示当前权限模式 banner——一眼能看到自己在哪个模式。
  3. 团队规定:任何在生产相关项目使用 bypassPermissions 的动作必须 1on1 报备。规则可能不会被严格执行,但它能让"开 bypass"变成一个心理上需要犹豫的动作。

5.4 hooks 失败被静默吞掉

反模式:Hook 脚本因为 command not foundpermission denied 静默失败,工程师以为"hook 在保护我",实际上没有。

防御

  • Hook 脚本必须有明确的错误处理——失败时输出可读 stderr。
  • 定期运行 claude --check-hooks 或自定义验证脚本,确认 hooks 都活着。
  • 不要把"hooks 失败"等同于"放行"——某些场景应该是"hooks 失败时禁止动作"。

Hook 健康度自检脚本:写一个简单的 self-test,每周自动跑一次,验证所有 Hook 是否正常工作:

#!/bin/bash
# .claude/hooks/self-test.sh
# 每周一 9 点通过 cron 跑一次

set -e
echo "## Hooks Self-Test — $(date)"

# 测试 secret 检测 hook
echo "test_key=sk_live_abcdef123456" > /tmp/hook-test.txt
if node .claude/hooks/check-secret-leak.js "/tmp/hook-test.txt" 2>/dev/null; then
  echo "❌ FAIL: secret leak hook didn't catch obvious test pattern"
  exit 1
else
  echo "✅ PASS: secret leak hook works"
fi

# 测试大文件检测 hook
dd if=/dev/zero of=/tmp/big-file.bin bs=1M count=10 2>/dev/null
if node .claude/hooks/check-big-file.js "/tmp/big-file.bin" 2>/dev/null; then
  echo "❌ FAIL: big file hook didn't catch 10MB file"
  exit 1
else
  echo "✅ PASS: big file hook works"
fi

rm -f /tmp/hook-test.txt /tmp/big-file.bin
echo "All hooks healthy."

如果 self-test 失败,立即报警(Slack / PagerDuty / 邮件)。不要让工程师"误以为 hooks 在保护"——验证一次胜过假设一百次

5.5 Skills 中嵌入未验证的外部脚本

反模式:从网上 copy 一段 curl xxx | sh 的安装脚本塞进 Skill,每次 Skill 执行时都跑一遍。

后果:远端脚本被劫持时,Skill 的每次运行都会执行恶意代码。

防御

  • Skills 中的所有外部下载必须 pin 到具体版本 / 哈希。
  • Skills 一旦稳定就 pin 住——不要让它"自动获取最新版本"。
  • 团队 Skill 库定期 audit,把所有外部依赖列出来评估风险。

Skill 安全审计的"三步法"

  1. 静态扫描:写一份 audit 脚本,扫描所有 .claude/skills/**/*.{sh,js,py} 中的外部 URL、curl 命令、wget 命令、远端 import。把结果输出到 .claude/skills-audit.md
  2. 依赖图谱:让 Claude 协助生成"Skill 依赖图谱"——哪些 Skill 调用哪些外部资源、哪些 Skill 又调用其他 Skill。当一个外部资源被多个 Skill 共享时,它的安全等级应该相应提高。
  3. 季度 audit 会议:每季度一次专门的"Skills 安全 audit 会",团队一起 review 当前 Skills 库,淘汰过时 Skill、收紧依赖、更新版本。

让 Claude 协助起草 audit 脚本:

#!/bin/bash
# .claude/scripts/skills-audit.sh

echo "## Skills 外部依赖 audit — $(date)"
echo
for skill in .claude/skills/*/; do
  echo "### $(basename "$skill")"
  echo
  # 扫描 curl / wget / npm install 等外部下载
  grep -rE 'curl |wget |npm install |pip install |go get ' "$skill" 2>/dev/null | sed 's/^/    /'
  echo
done

跑一次脚本就能拿到当前 Skills 库的"对外依赖清单",作为 audit 会议的输入。


六、PM 与工程师的安全边界差异

6.1 PM 视角:定义"哪些功能/数据是敏感的"

PM 不需要懂 settings.json,但必须能回答:

  • 哪些用户数据属于"绝不能泄漏"(密码、支付信息、隐私设置)
  • 哪些功能属于"必须人工二次确认"(删除账户、转账、批量操作)
  • 哪些场景的故障会触发法律/合规风险(GDPR、个保法、PCI-DSS)

PM 把这些约束转化为"业务级安全清单",工程师再翻译为 deny 规则与 Hooks。

PM 安全清单的"四象限"模板:PM 可以用一个简单的二维表格梳理业务安全敏感点——

可逆不可逆
影响小普通配置修改一次性发送的内部通知
影响大全员功能开关删除用户账户、转账、批量发送营销邮件

每个象限的处理建议:

  • 左上(可逆 + 影响小):放心交给 AI 协助开发,普通流程即可
  • 左下(可逆 + 影响大):开发可由 AI 协助,生产开关切换需人工
  • 右上(不可逆 + 影响小):开发由 AI 协助,触发条件需人工二次确认
  • 右下(不可逆 + 影响大):开发可由 AI 协助,但所有触发链路需多重确认 + 操作日志 + 撤销窗口

PM 把这份四象限按业务功能逐个填空,工程师拿到后翻译成对应的代码层防护:

  • 多重确认 → 二次密码确认 / 短信验证 / 邮件确认链接
  • 操作日志 → 审计表(audit log)+ 监控告警
  • 撤销窗口 → "30 天可恢复"机制(如删除账户的"软删除"模式)

6.2 工程师视角:把 PM 定义的敏感性翻译为 deny 规则

工程师收到 PM 清单后,需要:

  • 找到对应代码路径(例如"用户密码"对应 src/auth/password.ts
  • 加入 deny 列表(Edit(src/auth/**) 进 plan 模式)
  • 配置 Hooks 监控(任何对该路径的写操作都跑额外 lint + 强制 review)
  • 在 CLAUDE.md 里说明"为什么这块敏感"

翻译过程中的常见失真:PM 的语言("用户隐私"、"支付信息")与工程师的语言("数据库表"、"代码路径")之间存在天然鸿沟。常见失真包括——PM 说"保护用户密码",工程师只锁了 src/auth/password.ts,但忘了 src/auth/reset-password.tssrc/auth/oauth-callback.tssrc/admin/users.ts 等周边文件也可能触及密码逻辑。翻译时建议工程师与 PM 一起做一次"路径走读"——PM 描述用户场景,工程师同步指出场景涉及的所有代码路径,确保 deny 规则覆盖完整的"风险面"而非"风险点"。

6.3 跨角色协作:合规审查与代码审查的协同

合规审查与代码审查不应分割。建议每月一次"安全清单同步会":

  • PM 列出本月的新业务/新风险
  • 工程师列出本月的新 deny 规则与 Hooks 改动
  • 双方对照"业务需要保护的 vs 实际配置保护的"
  • 找出 gap,下个月补齐

同步会的"五个固定议题"

  1. 新功能/新接口的安全等级评估——本月上线的功能里,哪些涉及敏感数据?哪些有人工二次确认机制?哪些有审计日志?
  2. 本月 AI 出错事件回顾——.claude/incidents.md 里新增了哪些事件?根因是什么?是否需要更新 deny 规则?
  3. deny 规则覆盖度核查——业务清单上的"敏感"项是否都在 settings.json 里有对应保护?
  4. 法规变更追踪——本月有没有新的合规要求(GDPR 解读更新、个保法实施细则、行业标准修订)?是否需要调整流程?
  5. 同步会本身的 review——上次会议的 action item 完成了多少?拖延的原因是什么?

每月会议留下书面纪要,归档到 .claude/security-meetings/YYYY-MM.md。半年累积下来,这些会议纪要本身就是团队"安全成熟度"的最佳量化指标——通过翻阅历次纪要,新人能快速理解团队过去面对过哪些风险、做出过哪些决策、为什么形成现在这套规则。

6.4 团队级"安全行为公约"

把这一节的所有原则浓缩为一份团队公约,贴在 wiki 第一页:

## 团队 Claude Code 安全公约(v1.0)

1. 生产相关项目永不开 `bypassPermissions`
2. `.env` / secrets / credentials 文件 Claude 不读、不写、不引用
3. prompt 中粘贴日志前必须脱敏
4. git push / kubectl apply / pnpm publish 永远手动确认
5. 数据库 migration Claude 只生成、不执行
6. 新项目从 plan 模式起步,逐步建立信任
7. 任何 AI 出错事件必须记入 .claude/incidents.md
8. 每月一次安全清单同步会,全员参与

签字:工程团队全员、产品团队全员
日期:[填写]

公约不是装饰,而是强制规则。新人入职第一天读、每月会议引用、年度审查更新。这一份公约的存在,往往比一万行 settings.json 更能塑造团队的安全文化。

公约维护的"三大原则"

  1. 不要过度膨胀。8-12 条是公约的健康长度,超过 20 条意味着没人会真的读完。如果某条原则已经被工具自动化(例如 deny 列表),可以从公约中移除——公约只保留"工具无法 100% 强制、需要团队自觉"的部分。
  2. 每条公约都要有"为什么"。每条原则后面挂一段 50-200 字的"背景注释",解释这条规则的来源(来自哪次事故、哪条法规、哪种风险)。规则的"知其所以然"才能让规则在压力情境下被遵守。
  3. 每年一次"公约 review"。技术栈变了、业务变了、风险也会变。一份去年还有效的公约,今年可能已经成为团队效率的负担。把每年一月作为公约 review 月,全员参与重新签字——这一仪式本身就是文化的更新。

安全文化的最终衡量:一个团队的安全文化是否健康,不取决于 settings.json 多严密、Hooks 多复杂,而取决于一个简单的问题——"团队成员遇到不确定动作时,是默认前进还是默认询问?"。前者称为"风险偏好型文化",后者称为"风险规避型文化"。AI 协作时代的工程团队应当坚定地选择后者——因为 AI 能放大团队的效率,也能放大团队的错误。当工具变得越来越强大时,"默认询问"的文化是把"放大错误"的尾部风险压在可接受范围内的最后一道防线。


总结

权限边界不是用来限制 AI 的,而是用来保护人类——保护工程师不在疲劳时做错决定、保护团队不被某次失误拖垮、保护用户不被未经审查的代码影响、保护组织不被一次外部攻击撕裂。本节给出的"权限三层模型 + Claude Code 机制 + 五类高风险动作 + 信任曲线 + 反模式 + 团队公约"组成了一套完整的防御体系,目标只有一个——让"AI 协作"在解放生产力的同时,不让责任链断裂

最重要的一条心法:当你犹豫"这个动作是否可以让 Claude 自动执行"时,默认选择"不行"。安全设计的代价是工程师每天多按几次"批准"按钮(成本:每次 2 秒);安全设计失败的代价是某天某次的灾难性事故(成本:可能数小时到数月恢复时间 + 信任损失 + 可能的法律责任与商业赔付)。两者之间的赔率比悬殊到惊人,永远站在保守的一侧不会错。这条心法听起来朴素,但它是把"防御纵深"思想内化为肌肉记忆的最直接路径。任何一个能在压力情境下默认问一句"我是不是该再次确认一下"的工程师,都已经走在了团队安全文化的正确道路上,而这种朴素的谨慎会随着时间持续产生显著的复利效应。

下一节 7.4 将进入"心法层"的最后一节——Boris Cherny 的 9 条实战心法。这 9 条心法是 Anthropic Claude Code 团队在多个真实项目中沉淀出的精华,与本节的安全边界形成互补:本节告诉你"不要做什么",下一节告诉你"做对的事"。

留给读者的两个习题:

  1. 在你当前项目里写一份 .claude/settings.json 的 deny 列表,至少包含 10 条规则。每条规则配一行说明"为什么禁止"。
  2. 与团队对齐一份"团队 Claude Code 安全公约",至少包含 5 条原则。让所有 PM 与工程师签字,贴在团队 wiki 第一页。

这两个习题做完,你会发现"安全"不再是抽象的合规要求,而是被结构化嵌入工作流的具体动作。

额外建议:把这两份文档放在团队 onboarding 流程的"必读"清单里。新人入职第一天就读、第一周做小测验。这样做的目的不是考核,而是让新人在最容易接受规则的窗口期,把安全文化内化为本能反应。半年后这位新人变成 senior,他会自然而然地把这套思维方式传递给下一批新人——这是文化传承最稳定的路径。安全文化从来不是"靠制度强压",而是"靠每一代工程师的言传身教"。Claude Code 的工具与文档可以加速这一传承过程,但不能替代它。

延伸阅读