Skip to main content
CC Safety Net 通过语义分析区分允许的命令形式和破坏性的命令形式。本页列出分析器允许的命令形式。 部分允许项取决于安全级别。标记为仅 standard 的行在启用 strict 或 paranoid 后会被移除。 本页是允许命令的参考。被阻止的形式见被阻止的命令,有序防护流程见架构,分类器行为见分析引擎。
灾难性保护在每个安全级别都生效。根目录和主目录的递归删除、受保护的 Git 元数据以及规范 policy.json 始终被阻止。本页列出的命令形式、allow_paths、worktree 模式和单条规则的 off 覆盖都不会放宽这些保护。

Git 命令

纯分支名获得允许的前提是:它没有写成路径形式,也没有指向解析后 git 工作目录中已存在的条目。与已有文件或目录同名的分支会被阻止,拒绝信息指向 git switch。路径形式见被阻止的命令。

文件系统命令

rm -rf 按目标分类,第一个匹配项生效。根目录或主目录目标(/、~、$HOME)、受保护的 Git 元数据、当前工作目录本身(rm -rf .),以及当前工作目录就是主目录的情况,在所有级别都被阻止。当前工作目录外的其他字面路径也会被阻止,除非它们是已识别的临时目标或配置的允许路径。临时路径和当前工作目录内的路径是允许的。请注意区别:rm -rf ./subdir 是允许的,但 rm -rf .(当前工作目录本身)被阻止。 在此基础上还有两项与级别相关的调整:
  • 动态目标(rm -rf "$target"、反引号、替换)在 standard 中允许,一旦启用 fail-closed 能力就会被阻止。standard 对对抗性或动态生成的命令文本只提供尽力保护。
  • 启用 CC_SAFETY_NET_PARANOID_RM=1 后,即使在当前工作目录内,非临时的递归强制删除也会被阻止,因此 rm -rf ./cache 不再通过。临时目标和配置的允许路径仍然可以通过。

配置的允许路径

destructive_command_protection.allow_paths 下列出的绝对目录或以 ~/ 开头的目录会被当作受信任的临时根目录。它们在每个安全级别都生效,适用于 rm、PowerShell Remove-Item 和 find -delete。 允许路径不会放宽其他任何东西。它既不放宽敏感路径保护,也不放宽拒绝路径。它无法覆盖根目录、主目录或受保护的 Git 元数据。即使某个仓库位于允许路径内,rm -rf 该仓库的 .git 仍会被阻止。由于动态目标先于允许路径分类,允许路径永远不会作用于无法验证的目标。等于或包含 $HOME 的条目在校验时和规范化后都会被拒绝,而经符号链接逃逸出允许路径的情况也不在覆盖范围内。

Heredoc 数据消费者

标准输入上不展开的 heredoc,如果其消费者只是存储或发布正文,那么正文属于数据而不是程序,因此永远不会被当作命令文本扫描。消费者必须是字面量 cat、tee、git apply、git commit、gh pr create 或 gh issue create;heredoc 必须是该命令唯一的输入重定向;cat/tee 也不能把内容送入输出进程替换(>(...))。此项允许在每个级别都成立,strict 和 paranoid 也不例外。 heredoc 必须是不展开的:分隔符带引号(<<'EOF'),或者分隔符不带引号且正文中不含 $、反引号或反斜杠,这样 shell 就没有需要展开或转义处理的内容。不带引号且含有这三个字符之一的正文会经过 shell 展开或转义处理,因此在 standard 中仍会被扫描,启用 fail-closed 后则直接被拒绝。heredoc 之外的命令仍会分析。cat <<'EOF' && rm -rf ~ 会因 rm 被阻止。对于 cat、tee、git commit、gh pr create 和 gh issue create,分隔符带引号的正文在提取敏感路径前还会被遮蔽,因此正文里提到机密文件名不会阻止提交。不带引号的正文即使通过关卡也不会被遮蔽,其中形似文件名的 token 仍会被提取。git apply 的正文仍对路径提取可见,因为 patch 会列出它写入的文件。完整关卡以及 standard 如何处理未通过关卡的 heredoc,见 Heredoc 分析。

仅标准允许

这些形式在 standard 中允许,启用 strict 或 paranoid 后则会被拒绝。这不是疏漏。standard 对对抗性或动态输入只能尽力保护。 带引号赋值的延后判定范围很窄。赋值本身不执行任何操作,带引号的展开始终是一个 argv word,无法拆成命令加标志。只要分析器无法证明某处引用属于这类数据用法,赋值时的阻止就会保留:未加引号的展开(env $W)、位于命令位置的任何展开(即使带引号)、命令替换内的引用,以及未加引号的 heredoc 正文中的引用。把值交给 shell 则由下游拦截:eval "$W"、bash -c "$W" 和 echo "$W" | sh 都会被拒绝,因为无法验证 shell 的执行来源。 对生成命令的这项放行只看命令的形态,不看命令出自谁手,也没有一份可信生成命令的清单。只有 CMD 同时满足以下条件时,eval "$(CMD)" 和 source <(CMD) / . <(CMD) 才会放行:
  • 只有一条简单命令,没有重定向,也没有嵌套命令;
  • 所有词都是字面量,开头没有环境赋值;
  • 头部 basename 既不是远程抓取命令(curl、wget、fetch、aria2c、http、https、xh、xhs、nc、ncat、netcat),也不是 shell 或 sudo、env 这类标准命令包装器。
分析器仍会分析 CMD 本身,因此 eval "$(rm -rf /)" 会被阻止。不检查的是 CMD 打印出来的那段 shell:standard 由此把信任扩展到了每一条字面本地命令的输出,包括 eval "$(cat somefile)" 这样的形态。仍被阻止的形态见生成命令的 eval 与 source。
资源耗尽限制不属于此项权衡。超出解析器递归或结构校验上限的命令在每个级别都会被拒绝,standard 也不例外。

设备命令

dd、mkfs 和 shred 在每个级别都会被分析,但只有真正具有破坏性的形式才会被阻止。

PowerShell 命令

把 shell 模式设为 posix 会完全禁用 PowerShell 删除规则,但仍保留 git.reset-hard、rm.recursive-force-root-or-home 等跨 shell 规则。在 auto 模式下,分析器会识别显式的 Remove-Item,包括出现在 ;、换行、&& 或 || 之后的命令。Get-Content、Set-Content、Add-Content、Copy-Item、Move-Item 同样会被识别,gc、cp 之类别名在参数写成 PowerShell 路径表达式时也会被识别。

敏感路径允许

敏感路径保护是覆盖受支持形式的一组有界模式,因此某些提到敏感文件名的形式仍然允许。 其中两项允许的边界很明确,值得了解:
  • env 模板。 .env.example、.env.sample、.env.template 和 .env.defaults 这几个精确基名,以及任何以 .env.example. 或 .env.sample. 开头的名称,例如 .env.example.local,会在其他敏感路径规则运行前豁免。因此,即使位于受保护的主目录内也可读可写。这种前缀形式不适用于另外两个模板:.env.template.local 和其他所有 .env.* 名称一样,会被 secret.pattern.env-variant 阻止。
  • 供应商目录。 当任意路径段是 node_modules 或 __pycache__,或者出现相邻的 vendor/bundle 或 vendor/cache 组合(单独一个 vendor 段不算)时,恰好有两组规则被抑制:扩展名规则(.pem、.p12、.key 等)和宽泛的无扩展名密钥基名规则 secret.pattern.ssh-key-basename(*_rsa、*_dsa、*_ed25519、*_ecdsa)。其余规则在那里照常生效。node_modules/x/.env 和 node_modules/x/id_rsa 仍会被阻止。.git 不在跳过集合内,因此 .git 树内的密钥材料(例如 .git/hooks/deploy_key_rsa)和在其他任何位置一样匹配规则。
standard 从不放宽对敏感内容的访问,也从不放宽配置的拒绝路径。cat ~/.ssh/id_rsa、find ~/.ssh -type f -exec cat {} +、find ~/.ssh -type f -fprint .env、test -f ~/.ssh/id_rsa && cat ~/.ssh/id_rsa 和 test -f "$(cat ~/.ssh/id_rsa)" 在 standard 中同样保持阻止。拒绝路径及其子路径在内置规则之前匹配,并且不受两项仅 standard 放宽的影响。

Worktree 模式例外

使用 CC_SAFETY_NET_WORKTREE=1 时,CC Safety Net 会在验证 linked Git worktree 后允许选定的本地丢弃命令。如果验证失败,命令仍然被阻止。 worktree 模式启用后,以下命令在 linked worktree 内是允许的:
  • git restore <file> 和 git restore --worktree <file>
  • git checkout -- <file>、git checkout <path>、git checkout <ref> -- <file>、git checkout --force,以及有歧义的多位置参数 checkout 形式
  • git switch --discard-changes 和 git switch -f / --force
  • git reset --hard 和 git reset --merge
  • git clean -f(以及 -fd 这类组合标志)
  • git rm --force / -f
即使在 linked worktree 内,以下命令仍然被阻止,因为它们的影响超出本地工作树:
  • git push --force 会影响远程。
  • git branch -D 会影响共享引用。
  • git stash drop / git stash clear 会影响多个 worktree 共享的 stash。
  • git worktree remove --force 可能删除另一个 worktree。
下面的临时根目录放宽是另一条独立路径:当操作数本身就是受信任的临时根目录下的一次性 worktree 目录时,这条路径可以放行 git worktree remove --force。 Worktree 模式只放宽 git 本地丢弃规则。它不涉及文件系统、设备或 PowerShell 规则,也绝不放宽 Git 元数据保护:在 linked worktree 内,rm .git、rm -rf <resolved gitDir>、rm -rf <commonDir> 以及重定向 > .git 仍会硬停止,因为标记文件解析出的 Git 目录同样受保护。

临时根目录放宽

在受信任的临时根目录下的一次性仓库中运行 git 时,Git 规则同样会放宽。这条路径独立于 worktree 模式,不需要 CC_SAFETY_NET_WORKTREE=1。 除 git.push-* 外,所有 Git 规则都可以通过这条路径放宽。git.ssh-env 和 git.alias-config 在放宽判定之前就已得出结论,因此同样不会放宽。目标仓库是解析后 git 工作目录向上最近的、含有 .git 条目的祖先目录。该仓库根目录必须位于受信任的临时根目录之下,本身不能是临时根目录,也不能是工作区(原始 cwd)的祖先或子目录。它的 .git 必须是实际存在的目录条目;.git 缺失或是符号链接时规则继续生效。 临时根目录下的 linked worktree,.git 是文件。这种情况下只有本地丢弃类规则才能放宽,而且要同时满足两点:worktree 信息通过验证,命令通过 worktree 模式所列的同一组「不可放宽的本地丢弃」。因此其中的 branch、stash 和 tag 操作仍然被阻止,git reset --hard <ref> 改动共享状态,在这里同样不会放宽。 出现以下情况时不会放宽:命令行中带 --git-dir 或 --work-tree、存在 GIT_DIR 一类的环境变量覆盖,或命令来自展开后的命令行 git 别名。 git worktree remove --force 按操作数判断,而不是按仓库判断。remove 之后必须只有一个字面操作数,它必须是绝对路径,不含空白、$、反引号和 glob 字符,并且已经是一个实际存在的非符号链接目录,其真实路径位于受信任的临时根目录之下,本身不是临时根目录,也与工作区无关。只有解析器判定为变量展开的词才会先做展开。 配置的 allow_paths 不会扩大这项放宽。它只在 rm 的目标分类中读取,因此在其中加入某个路径,并不会让该路径下的仓库对 Git 规则而言变成一次性仓库。 完整条件见分析引擎。
如果 CC Safety Net 阻止了你认为安全的命令,运行 npx cc-safety-net explain "<command>" 可以查看完整分析并了解原因。它的标志见 CLI 命令,更完整的诊断流程见故障排除。
最后修改于 2026年9月21日