Skip to main content
这是技术指南的最后一页。它不介绍新行为,只说明架构分析引擎中各项设计的依据与取舍。要了解系统做什么,请先读那两页。要了解为什么这样做,请读本页。 CC Safety Net 源于一次真实事故:一个 AI 编码智能体删除了整个主目录。这起事故依然成立,但已不再是最前沿的威胁:Claude Code 现已为这类关键路径内置了确定性断路器,而工作区内的破坏性 git 命令仍没有这样的断路器。每项设计选择都服务于同一个目标:在智能体执行破坏性命令之前就阻止它们,并且绝不制造虚假的安全感。

使用语义分析,而不是通配符模式

编码智能体支持使用通配符匹配的 deny rule,例如匹配 git reset --hard 的通配符规则。这类规则拿原始命令字符串去和模式比对,因此空格、标志顺序或命令包装上的任何变化,都可能让阻止悄无声息地失效。调换标志顺序(rm -r -f /)、放进 shell 包装器(sh -c "rm -rf /")或藏在解释器后面,都能绕过字符串匹配。 CC Safety Net 会解析每条命令,再交给理解 gitrmRemove-Itemfindxargsparallel 实际选项语法的分析器。因此,判定基于命令的作用,而不是命令的外观 代价是复杂性:解析器必须正确处理 shell 语法,每个受支持的命令都需要自己的分析器。收益是对最要紧的那些命令具备抗绕过能力。管线本身见架构,每个分析器的具体行为见分析引擎

固定顺序,并先执行始终启用的保护

在每个集成中,每次工具调用都经过相同的有序阶段。其中两个阶段会刻意在加载策略快照之前运行:用户和项目策略文件的保护,以及 Git 元数据保护。 这个顺序很重要。配置之后才运行的保护,不会比配置本身更可靠,而被攻陷的智能体很可能先修改配置。这两个防护在读取策略文件前就能拒绝请求,因此不携带配置状态。预设或 override 无法放宽它们,被保护文件中的设置也关不掉这两个防护。代价是这类拒绝不能报告安全级别或 fallback 原因,因为此时两者尚未确定。这里用诊断细节换取无条件保护。 敏感路径保护则位于这条线的另一侧,在快照之后执行。它确实受策略控制,因为哪些路径算敏感本就该由本地决定,而且拒绝路径只有在你能添加自己的路径时才有意义。 具体阶段表见架构

无法完成分析时 fail closed

CC Safety Net 无法完成分析时会阻止,而不是允许:
  • 防护中任何位置抛出的错误都会在每个入口点变为拒绝,并归因于抛出错误的阶段。
  • 超过工具输入边界或解析器预算都会导致拒绝,在所有安全级别下都是如此。
  • Strict 模式把 fail-closed 进一步扩展到解析器无法完全理解的命令,以及它无法验证的破坏性目标。
道理很简单:fail-open 的安全网比没有安全网更糟,因为它会制造虚假的安全感。意外错误造成的阻止固然烦人,但还能补救;让破坏性命令通过则无从挽回。 无效配置刻意不在此列。 被拒绝的配置来源会被丢弃,不会转为一次拒绝。如果 rulebook 中的一个拼写错误就能阻止所有工作,那等同于对用户发起拒绝服务,只会促使人们卸载工具,而不是修复文件。这项约定和修复路径由配置恢复负责说明。 这些属性在每个信任边界的执行方式见安全模型

让智能体继续任务的拒绝方式

拒绝不是一种错误状态。它在当前会话中作为普通工具结果返回给智能体。正是这一行为决定了 CC Safety Net 如何撰写每一条阻止消息。 一句干巴巴的 permission denied 可能让智能体去重试类似命令,或者干脆停下整个任务。反复换着变体尝试,有可能撞上一种未受保护的写法,还会白白消耗智能体的轮次;停下整个任务则把一次安全动作变成一次停工。 因此,每条消息都力求给智能体一个有效的后续动作。原因会用平实的语言说明这条命令本会做什么,并在存在更安全的替代方案时点明该方案。每条规则还带有一个 intent,由它选择结尾指令:报告阻止并继续任务的其余部分、改用指定的替代方案、用更窄的明确目标重试、把操作交给用户,或者重构命令而不是穷举变体。即使内部错误触发 fail-closed 拒绝,intent 也会要求重构命令,不要重试。这样,工具意外失败时仍能引导智能体采取有用的应对措施。 这条指令刻意只是建议性的。没有任何机制强制智能体遵守;执行由防护完成,不服从的重试同样会被阻止。消息的意义在于让合规路径成为最省事的一条,从而在常见情况下,会话吸收一次阻止后就能继续前进。消息结构和完整的 intent 表见工作原理

最小依赖面

CC Safety Net 运行时只依赖一个延迟加载的软件包。命令段拆分、引号、重定向、命令替换和动态 word 来源等结构信息,都来自它自有的有界 POSIX 和 PowerShell 解析器,不依赖第三方语法库。选择自建解析器有以下原因:
  • 更小的依赖树意味着更小的供应链攻击面,而解析器是攻击者最想混淆的组件。
  • 分析需要通用 tokenizer 不会保留的事实,例如哪些 word 来自展开、哪个目标锚定在工作目录、使用了哪种引用形式。因此,自有解析器是让这些事实成为一等数据的唯一途径。
  • 解析器预算可以是固定常量而不是配置项,于是资源耗尽成为一种有界、可测试的失败模式,而不是开放式的失败。
  • 对于把 CC Safety Net 作为 hook 子进程运行的智能体,它在每次 shell 工具调用时都是全新启动,因此启动时间很重要,依赖越少冷启动越快。
解析器预算和各依赖项的用途见架构

Rulebook 系统

早期版本把自定义规则存为单个项目文件中的内联 JSON。CC Safety Net 出于四个原因改用了 rulebook 系统:
  • 共享rule addrule update 按指定 ref 从 GitHub 仓库获取 rulebook,并落盘到使用方自己的 rules/<name>/rulebook.json,使团队无需手工复制 JSON 即可共享阻止策略。落盘副本就是使用方仓库里的一个文件:人可以直接阅读,可以在 pull request 中评审,更新改了什么也能从 diff 看出来。
  • 完整性rule addrule update 会把 ref 解析到 commit,通过 HTTPS 获取文件(禁止重定向,响应的字节数和时间都有上限),再做 schema 验证,并要求 name 与来源一致。对 rulebook_version: 2,还会用该 rulebook 自身的 fixture 校验它自己的规则。任何一步失败的来源,都会在写入任何内容之前被拒绝。落盘之后没有再与上游内容比对的机制,此后与仓库中其他文件一样靠评审保证。
  • 范围:rulebook 支持独立的用户(全局)和项目范围,并使用不同配置目录。
  • 验证:rulebook 内容必须通过 schema 验证,才能影响阻止判定。
自定义规则严格只增不减:它们只能添加限制,绝不能放宽内置保护。这样信任边界才能保持简单。编写流程见自定义规则

使用分级级别,而不是一个设置

保护分为 standard、strict 和 paranoid 三个预设,而不是一个开关。是否阻止无法验证的命令,取决于命令的来源。 Standard 针对有人监督的会话做了优化:它阻止可识别的破坏性命令和敏感内容访问,同时容许无法解析但无害的文本,因此不会打断日常工作。面对对抗性或动态输入,它明确只提供尽力保护;当命令可能来自提示注入或其他不可信上下文时,它不是合适的设置。 Strict 和 paranoid 用额外限制换取确定性。Strict 阻止无法验证的内容;paranoid 还会阻止通常安全但偶尔会造成灾难的类别。设计上不会通过增加 standard 模式的解析启发式来填补缺口。静态分析无法确定的目标,不会因为增加猜测就变得安全。发现新缺口时,应为 strict 或 paranoid 添加 fail-closed fixture,并记录 standard 模式的残余风险。 各项能力仍可单独设置,任何 per-rule override 都能在 standard 下强制启用 strict tier 的规则。而任何 override 都做不到的,是削弱灾难性规则或始终启用的保护。级别见模式,各条边界的准确位置见分析引擎

纵深防御,而不是替代方案

CC Safety Net 不声称自己是完整的安全方案。它是纵深防御堆栈中的一层:
  • 权限 deny rule 提供快速且用户可配置的阻止。CC Safety Net 在权限系统之前运行,因此无论 deny rule 如何配置,它都会检查每条命令。
  • 操作系统级沙箱限制文件系统和网络访问,但不理解边界的操作是否具有破坏性。沙箱目录中的 git reset --hard 从沙箱角度看在技术上安全,但仍会造成严重误操作。
请把这几层组合起来用:deny rule 用于快速迭代,沙箱用于应对未知威胁和做隔离,CC Safety Net 用于对已知的破坏性模式提供抗绕过保护。见保护层比较

Worktree 放宽

Linked Git worktree 会产生可用性问题:在 worktree 中工作的开发者通常需要运行 git checkout -- .git reset --hard 来丢弃该 worktree 中的本地更改,但默认规则会把它们作为 local-discard 操作阻止。 Worktree 模式只放宽 local discard,不会全面关闭这条规则。目录必须通过验证,确实属于 linked worktree,而且没有任何设置重定向 Git 上下文。仅仅看起来像 worktree 并不够。验证无法完成时,命令仍会被阻止。 这项放宽刻意保持狭窄:所有影响远程的操作(force push、删除分支、丢弃 stash)仍被阻止,可能波及这个可丢弃 worktree 之外的 local discard 同样仍被阻止。具体条件和不可放宽的情况见分析引擎,启用方法见模式

后续阅读

技术指南先讲用户看到的流程,再讲设计依据。本页是第 5 步,也是最后一步。
  • 上一页:分析引擎说明这些取舍产生的具体分类行为,架构说明这些取舍支持的防护顺序。
  • 从头开始:工作原理以用户层面的深度说明同一套系统。
相关页面:安全模型说明这些决定保护的信任边界,已知限制说明它们不能解决的问题,配置恢复说明上文引用的 readydegraded 约定。
最后修改于 2026年8月31日