Git コマンド
素のブランチ名が許可されるのは、パスの形をしておらず、解決後の git の作業ディレクトリに実在するエントリも指していない場合だけです。実在するファイルやディレクトリと同じ名前のブランチはブロックされ、拒否メッセージは
git switch を案内します。パスの形についてはブロックされるコマンドを参照してください。
ファイルシステムコマンド
rm -rf は対象によって分類され、最初に一致した分類が採用されます。root やホームディレクトリの対象(/、~、$HOME)、保護対象の Git メタデータ、カレントディレクトリそのもの(rm -rf .)、カレントディレクトリがホームそのものである場合は、どのレベルでもブロックされます。カレントディレクトリの外にあるリテラルのパスも、既知の一時パスや設定済みの allow path でないかぎりブロックされます。一時パスと、カレントディレクトリ配下のパスは許可されます。この違いに注意してください。rm -rf ./subdir は許可されますが、カレントディレクトリそのものを指す rm -rf . はブロックされます。
その上で、レベルに応じた次の 2 つの調整が適用されます。
- 動的な対象(
rm -rf "$target"、バッククォート、コマンド置換)は standard では許可され、fail closed の機能が有効になるとブロックされます。standard は、敵対的な入力や動的に生成されたコマンド文字列に対してはベストエフォートです。 CC_SAFETY_NET_PARANOID_RM=1を設定すると、一時パス以外への再帰的な強制削除は、カレントディレクトリ配下であってもブロックされます。そのためrm -rf ./cacheは許可されなくなります。一時パスの対象と、設定済みの allow path は引き続き許可されます。
設定済みの allow path
destructive_command_protection.allow_paths に記載した絶対ディレクトリまたは ~/ で始まるディレクトリは、信頼された一時ルートとして扱われます。これはすべての安全レベルで、rm、PowerShell の Remove-Item、find -delete に適用されます。
allow path が他の範囲を広げることはありません。機密パス保護や deny path を緩和しません。ルート、ホーム、保護対象の Git メタデータを対象にはできません。リポジトリを含む allow path でも、そのリポジトリの .git に対する rm -rf はブロックされます。動的な対象が最初に分類されるため、検証できない対象には allow path が適用されません。$HOME と等しい、またはそれを含むエントリは、検証時と正規化後の両方で拒否されます。allow path から外へ出るシンボリックリンクは対象外です。
heredoc をデータとして受け取るコマンド
標準入力に対する展開されない heredoc で、読み取り側が本文を保存または公開するだけの場合、その本文はプログラムではなくデータです。そのため、本文をコマンド文字列としてスキャンすることはありません。読み取り側は、リテラルで書かれたcat、tee、git apply、git commit、gh pr create、gh issue create のいずれかである必要があります。また、その heredoc がコマンド内で唯一の入力リダイレクトであり、cat と tee については出力側のプロセス置換(>(...))につながっていないことも条件です。この許可は、strict と paranoid を含むすべてのレベルで有効です。
対象になるのは、展開されない heredoc だけです。デリミタが引用符で囲まれているもの(
<<'EOF')か、引用符がなくても本文に $、バッククォート、バックスラッシュが含まれないものが該当し、どちらもシェルが展開やエスケープ処理を行う余地はありません。引用符がなく、この 3 つの文字のいずれかが本文に含まれる場合は、シェルの展開やエスケープ処理を受けるため、standard では引き続きスキャンの対象になり、fail closed が有効な場合は拒否されます。heredoc の外にあるコマンドは、これまでどおり解析されます。cat <<'EOF' && rm -rf ~ は rm によってブロックされます。cat、tee、git commit、gh pr create、gh issue create では、デリミタが引用符で囲まれた本文を、機密パスの抽出前にマスクします。そのため、シークレットのファイル名を文章の中で触れただけでコミットがブロックされることはありません。引用符のない本文は、条件を通過する場合でもマスクの対象にはならないため、その中にファイル名らしいトークンがあれば抽出されます。git apply の本文は、patch が書き込むファイル名を含むため、パス抽出からは見える状態のままにします。条件の全体と、条件を満たさない heredoc を standard がどう扱うかについては、heredoc の解析を参照してください。
standard のみの許可
次の形式は standard では許可され、strict または paranoid を有効にすると拒否されます。これは見落としではなく、意図的なトレードオフです。standard は、敵対的な入力や動的な入力に対してはベストエフォートという位置づけだからです。
引用符付きの代入に対する判定の先送りは、適用範囲が狭く限定されています。代入自体は何も実行せず、引用符付きの展開は 1 つの argv の語のままなので、コマンドとフラグに分割されないためです。データとしての利用だとアナライザーが確認できない参照については、代入の時点でのブロックが維持されます。引用符なしの展開(
env $W)、コマンド位置でのあらゆる展開(引用符付きを含む)、コマンド置換の中での参照、引用符なしの heredoc 本文での参照が該当します。値をシェルに渡す操作は、その後の段階で検出されます。eval "$W"、bash -c "$W"、echo "$W" | sh は、いずれもシェルの実行元を検証できないため拒否されます。
生成コマンドの許可は、コマンドの形を見て判定するものであり、誰が書いたかは見ません。信頼できる生成コマンドの一覧はありません。eval "$(CMD)" と source <(CMD) / . <(CMD) を許可するのは、CMD が次の条件をすべて満たす場合だけです。
- 単純コマンドが 1 つだけで、リダイレクトも入れ子のコマンドもない
- 語がすべてリテラルで、先頭に環境変数代入がない
- 先頭のベース名が、リモート取得コマンド(
curl、wget、fetch、aria2c、http、https、xh、xhs、nc、ncat、netcat)でも、シェルでも、sudoやenvのような標準的なコマンドラッパーでもない
CMD 自体は引き続き解析するため、eval "$(rm -rf /)" はブロックします。検証しないのは CMD が出力するシェルです。つまり standard は、リテラルなローカルコマンドでありさえすれば、その出力を信頼します。eval "$(cat somefile)" のような形も含まれます。ブロックされたままの形については、生成されたコマンドの eval と sourceを参照してください。
リソース枯渇を防ぐための上限は、このトレードオフには含まれません。パーサーの再帰上限や構造的な検証の上限を超えるコマンドは、standard を含むすべてのレベルで拒否されます。
デバイスコマンド
dd、mkfs、shred はすべてのレベルで解析されますが、実際に破壊的な形式のみがブロックされます。
PowerShell コマンド
シェルモードに
posix を選ぶと、PowerShell の削除ルールは意図的にすべて無効になります。一方、git.reset-hard や rm.recursive-force-root-or-home などのクロスシェルルールは維持されます。auto モードでは、明示的な Remove-Item が検出されます。これは、;、改行、&&、|| の後にある場合も同じです。Get-Content、Set-Content、Add-Content、Copy-Item、Move-Item も同様に検出され、gc や cp のような別名も引数が PowerShell のパス式で書かれていれば検出されます。
機密パスに関する許可
機密パス保護は、サポート対象の形式に対する範囲が限定されたパターンセットです。そのため、機密ファイル名を含む一部の形式は引き続き許可されます。
この許可には、注意すべき境界が 2 つあります。
- env テンプレート。 正確なベース名
.env.example、.env.sample、.env.template、.env.defaultsと、.env.example.または.env.sample.で始まるすべての名前(.env.example.localなど)は、ほかのすべての機密パスルールより先に除外されます。そのため、保護対象のホームディレクトリ内でも読み書きできます。この接頭辞形式は、残りの 2 つのテンプレートには拡張されません。.env.template.localは、ほかのすべての.env.*名と同様にsecret.pattern.env-variantでブロックされます。 - ベンダー管理ディレクトリ。 パスセグメントが
node_modulesまたは__pycache__の場合、または隣接する組み合わせvendor/bundleまたはvendor/cacheがある場合(単独のvendorセグメントは対象外)、正確に 2 つのルールグループが抑制されます。拡張子ルール(.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など)は、ほかの場所と同様にルールに一致します。
worktree モードの例外
CC_SAFETY_NET_WORKTREE=1 を設定すると、CC Safety Net は Git の linked worktree であることを確認したうえで、一部のローカル破棄コマンドを許可します。確認できなかった場合、そのコマンドはブロックされたままです。
worktree モードが有効なとき、リンクされた 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/--forcegit reset --hardとgit reset --mergegit clean -f(-fdなどの結合フラグも含む)git rm --force/-f
git push --force:リモートに影響するgit branch -D:共有された ref に影響するgit stash drop/git stash clear:stash は worktree 間で共有されるgit worktree remove --force:別の 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 エントリを持つ祖先ディレクトリです。このリポジトリのルートは、信頼された一時ルートの配下にあり、一時ルートそのものではなく、ワークスペース(元のカレントディレクトリ)の祖先でも配下でもない必要があります。さらに .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 の後ろにあるリテラルのオペランドがちょうど 1 つで、絶対パスであり、空白、$、バッククォート、glob 文字を含まず、シンボリックリンクではない実在のディレクトリを指し、その実パスが信頼された一時ルートの配下にあり、一時ルートそのものではなく、ワークスペースとも無関係である必要があります。展開されるのは、パーサーが変数展開と判断した語だけです。
設定した allow_paths によって、この緩和が広がることはありません。allow_paths を読むのは rm の対象分類だけなので、そこにパスを追加しても、その配下のリポジトリが Git ルールにとって使い捨て扱いになるわけではありません。
詳しい条件は解析エンジンを参照してください。