使用语义分析,而不是通配符模式
编码智能体支持使用通配符匹配的 deny rule,例如匹配git reset --hard 的通配符规则。通配符模式把原始命令字符串与模式比较。空格、标志顺序或命令包装的任何变化都可能让阻止静默失效。重新排列标志(rm -r -f /)、放入 shell 包装器(sh -c "rm -rf /")或隐藏在解释器后都能绕过字符串匹配。
CC Safety Net 会解析每条命令,并把命令交给理解 git、rm、Remove-Item、find、xargs 和 parallel 实际选项语法的分析器。因此,判定基于命令的作用,而不是命令的外观。
代价是复杂性:解析器必须正确处理 shell 语法,每个受支持命令都需要自己的分析器。收益是对最重要命令的抗绕过能力。管线见架构,每个分析器的具体行为见分析引擎。
固定顺序,并先执行始终启用的保护
在每个集成中,每次工具调用都经过相同的有序阶段。其中两个阶段,即规范策略文件保护和 Git 元数据保护,会刻意在加载策略快照之前运行。 这种顺序就是设计重点。在配置之后评估的保护只能和配置一样可靠,而受损智能体首先会尝试修改配置。因为这两个防护在读取策略文件前拒绝,所以它们没有配置状态,preset 或 override 无法放宽它们,它们保护的文件也不能关闭它们。代价是这些拒绝不能报告安全级别或 fallback 原因,因为两者此时均未知。这是用诊断细节换取无条件保证的有意取舍。 敏感路径保护位于边界另一侧,在快照之后执行。策略可以控制它,因为哪些路径属于敏感路径确实是本地决定,并且 deny path 只有在你能添加自己的路径时才有用。 具体阶段表见架构。无法完成分析时阻止
CC Safety Net 无法完成分析时会阻止,而不是允许:- 防护中任何位置抛出的错误都会在每个入口点变为拒绝,并归因于抛出错误的阶段。
- 超过工具输入边界或解析器预算会在每个安全级别下拒绝。
- Strict 模式把 fail-closed 扩展到解析器无法完全理解的命令和无法验证的破坏性目标。
让智能体继续任务的拒绝方式
拒绝不是错误状态。它在活动会话中作为普通工具结果返回给智能体。此行为决定 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 系统:- 共享:可以从 GitHub 仓库获取 rulebook,并在 lockfile 中用 SHA-256 digest 固定,使团队无需复制 JSON 即可共享阻止策略。
- 完整性:使用前会根据 lockfile digest 验证远程 rulebook 内容。内联配置没有完整性机制。
- 作用域:rulebook 支持独立的用户(全局)和项目作用域,并使用不同配置目录。
- 验证:rulebook 内容必须通过 schema 验证,才能影响阻止判定。
使用分级级别,而不是一个设置
保护以 standard、strict 和 paranoid 三个 preset 提供,而不是单个开关,因为“是否应阻止无法验证的命令”的正确答案取决于命令来源。 Standard 针对有人监督的会话优化:它阻止可识别的破坏性命令和敏感内容访问,同时容许无法解析但无害的文本,因此不会中断日常工作。它对对抗性或动态输入明确只提供尽力保护。当命令可能来自提示注入或其他不可信上下文时,不应使用此设置。 Strict 和 paranoid 用摩擦换取确定性。Strict 阻止无法验证的内容;paranoid 还阻止通常没有问题但偶尔会造成灾难的类别。设计不会通过增加更多 standard 模式解析启发式来填补 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从沙箱角度看在技术上安全,但仍会造成严重误操作。
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 步。 相关页面:安全模型说明这些决定保护的信任边界,已知限制说明它们不能解决的问题,配置恢复说明上文引用的ready 和 degraded 约定。