1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code Auto Modeの安全設計——サンドボックスだけでは足りない理由とhookによる多層防御

1
Last updated at Posted at 2026-04-17

AnthropicがAuto Modeの安全設計について公式記事を公開した。

核心的なデータ: ユーザーは確認プロンプトの93%を承認している。つまり大多数のプロンプトは不要で、承認疲れを引き起こしている。Auto Modeはこれを安全分類器(Sonnet 4.6ベース)で自動化する。

だが「Auto Modeを有効にすれば安全」という理解は危険だ。公式記事自体が「careful human reviewの代替ではない」と明記している。分類器には2つの弱点がある。

  1. 誤検出(false positive): 安全なコマンドを「要確認」と判定する。$()を含むコマンド、パイプチェーン、複合コマンドが頻繁に引っかかる
  2. 分類器障害: Sonnetのインフラが落ちると、全てのコマンドが「要確認」になる。catlsも手動承認が必要になる

GitHub Issue #38537(リアクション61件)、#30435(リアクション33件)、#39259#38618。いずれもAuto Modeの分類器に起因する問題の報告だ。

hookを使えば、両方の問題に対処できる。

Auto Modeのサンドボックスの仕組み

まず、Auto Modeが何をしているか整理する。

通常モード(非Auto)では、Claude Codeはコマンドを実行する前に毎回ユーザーに許可を求める。Auto Modeを有効にすると、安全分類器が間に入る。

[通常モード]
Claude Code → ユーザーに確認 → 実行

[Auto Mode]
Claude Code → 安全分類器(Sonnet) → 安全 → 実行
                                   → 要確認 → ユーザーに確認

分類器は読み取り専用コマンド(lscatgrep等)を自動で許可し、破壊的コマンド(rmgit push等)をブロックする。理論上は合理的な設計だ。

だが「理論上」と「実際」は違う。公式記事のデータでも、分類器のfalse negative率(危険な操作を見逃す率)は17%。5回に1回は見逃す。

問題1: 安全なコマンドが止まる(false positive)

Issue #38537の報告。$(date +%Y%m%d)のようなコマンド置換を含むコマンドが「要確認」に分類される。

# これらが止まる
mkdir backup-$(date +%Y%m%d)     # コマンド置換
cat file.txt | grep "pattern"    # パイプチェーン
cd /tmp && ls -la                # 複合コマンド

mkdircat | grepcd && lsも破壊的ではない。だが分類器はコマンドの構造的な複雑さを「危険シグナル」と解釈する。

結果として、Auto Modeにしているのに頻繁に確認ダイアログが出る。自律稼働させている場合、ここで止まる。

問題2: 分類器がダウンすると全停止

Issue #39259#38618の報告。安全分類器のインフラ(Sonnet)が障害を起こすと、分類結果が返らなくなる。

このとき、Claude Codeはフェイルセーフとして全てのコマンドを「要確認」に格下げする。cat README.mdですら手動承認が必要になる。

自律稼働中にこれが起きると、完全に止まる。寝て起きたら「承認待ち」で一晩中何もしていなかった、という事態になる。

hookによる多層防御(Defense-in-Depth)

セキュリティの世界では「多層防御(Defense-in-Depth)」が基本原則だ。1つの防壁に頼らず、複数の層で守る。

Auto Modeの分類器は1つの層だ。hookをもう1つの層として追加する。

[多層防御モデル]
Claude Code → hook(PreToolUse) → 安全分類器(Sonnet) → 実行
              ↓ exit 2: ブロック    ↓ 要確認: ユーザーに確認

[分類器障害時]
Claude Code → hook(PreToolUse) → 分類器ダウン → hook(PermissionRequest) → 実行
              ↓ exit 2: ブロック                   ↓ allow: 自動承認(安全なコマンドのみ)

hookには2つの役割がある。

  1. PreToolUse hook(auto-mode-safe-commands): 分類器のfalse positiveを補正する。安全なコマンドを自動許可する
  2. PermissionRequest hook(classifier-fallback-allow): 分類器が落ちたときに、読み取り専用コマンドだけを自動承認する

設定1: auto-mode-safe-commands

分類器が「要確認」と誤判定するコマンドを、hookで自動許可する。

#!/bin/bash
# auto-mode-safe-commands.sh — Fix Auto Mode false positives on safe commands

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0

APPROVE=false
REASON=""

# Read-only file commands
if echo "$COMMAND" | grep -qE '^\s*(cat|head|tail|ls|tree|find|wc|file|stat|du|df)\s'; then
    APPROVE=true; REASON="Read-only file inspection"
fi

# Text search
if echo "$COMMAND" | grep -qE '^\s*(grep|rg|ag|ack)\s'; then
    APPROVE=true; REASON="Text search"
fi

# Git read-only
if echo "$COMMAND" | grep -qE '^\s*git\s+(status|log|diff|show|branch|tag|blame)'; then
    APPROVE=true; REASON="Git read-only"
fi

# Safe command substitution (e.g. mkdir backup-$(date +%Y%m%d))
if echo "$COMMAND" | grep -qE '\$\(date\s'; then
    OUTER=$(echo "$COMMAND" | sed 's/\$([^)]*)/SUBST/g')
    if echo "$OUTER" | grep -qE '^\s*(echo|printf|mkdir|touch)\s'; then
        APPROVE=true; REASON="Safe command with date substitution"
    fi
fi

# Output allow decision or stay silent
if [ "$APPROVE" = true ]; then
    jq -n --arg reason "$REASON" \
        '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":$reason}}'
fi
exit 0  # No opinion if not approved — let classifier decide

ポイントは最後のexit 0だ。パターンにマッチしなければ何も出力しない。分類器の判断を上書きしない。安全だと確信できるコマンドだけを自動許可する。全パターンはcc-safe-setupのexamples/auto-mode-safe-commands.shで確認できる。

settings.jsonへの登録:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "~/.claude/hooks/auto-mode-safe-commands.sh"
      }]
    }]
  }
}

設定2: classifier-fallback-allow

分類器がダウンしたとき用のフォールバック。PermissionRequestフックとして設定する。

PreToolUseとPermissionRequestの違いを理解する必要がある。

  • PreToolUse: コマンド実行前に毎回呼ばれる。allowを返すとユーザー確認をスキップ
  • PermissionRequest: ユーザーに確認ダイアログが表示される直前に呼ばれる。allowを返すとダイアログをスキップ

分類器が正常なら、安全なコマンドはPermissionRequestまで到達しない(分類器が自動許可するため)。分類器がダウンしたときだけ、全コマンドがPermissionRequestに到達する。ここでclassifier-fallback-allowが安全なコマンドを自動承認する。

#!/bin/bash
# classifier-fallback-allow.sh — Allow read-only commands when classifier is down

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0

BASE=$(echo "$COMMAND" | awk '{print $1}')
ALLOW='{"hookSpecificOutput":{"hookEventName":"PermissionRequest","permissionDecision":"allow","permissionDecisionReason":"Classifier fallback"}}'

case "$BASE" in
    cat|head|tail|ls|tree|find|wc|file|stat|du|df|which|readlink)
        # find -delete is NOT read-only
        echo "$COMMAND" | grep -qE '\s-delete' && exit 0
        echo "$ALLOW"; exit 0 ;;
    grep|rg|ag|ack)
        echo "$ALLOW"; exit 0 ;;
    git)
        SUBCMD=$(echo "$COMMAND" | awk '{print $2}')
        case "$SUBCMD" in
            status|log|diff|show|branch|tag|blame|ls-files)
                echo "$ALLOW"; exit 0 ;;
        esac ;;
    echo|printf|pwd|env|date|uname|whoami|id)
        echo "$ALLOW"; exit 0 ;;
    jq|yq)
        echo "$ALLOW"; exit 0 ;;
esac
exit 0  # Unknown command — don't interfere

settings.jsonへの登録(PreToolUseではなくPermissionRequest):

{
  "hooks": {
    "PermissionRequest": [{
      "matcher": "Bash",
      "hooks": [{
        "type": "command",
        "command": "~/.claude/hooks/classifier-fallback-allow.sh"
      }]
    }]
  }
}

2つのhookの役割分担

整理するとこうなる。

状態 auto-mode-safe-commands (PreToolUse) classifier-fallback-allow (PermissionRequest)
分類器が正常 + 安全コマンド hookがallow → 実行 到達しない(分類器が先に許可)
分類器が正常 + 危険コマンド hookはスルー → 分類器が判定 分類器が「要確認」→ ユーザーに確認
分類器が正常 + false positive hookがallow → 実行 到達しない
分類器がダウン + 安全コマンド hookがallow → 実行 hookがallow → 実行
分類器がダウン + 危険コマンド hookはスルー hookはスルー → ユーザーに確認

重要なのは、危険なコマンドは誰も自動許可しないこと。rmgit push --forceDROP TABLEはどの層でもスルーされず、必ずユーザー確認に回る。

さらに守りを厚くする: destructive-guardとの併用

auto-mode-safe-commandsとclassifier-fallback-allowは「安全なコマンドを止めない」ためのフックだ。逆方向——「危険なコマンドを確実に止める」——にはdestructive-guardとbranch-guardが必要だ。

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/destructive-guard.sh" },
          { "type": "command", "command": "~/.claude/hooks/branch-guard.sh" },
          { "type": "command", "command": "~/.claude/hooks/auto-mode-safe-commands.sh" }
        ]
      }
    ],
    "PermissionRequest": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "~/.claude/hooks/classifier-fallback-allow.sh" }
        ]
      }
    ]
  }
}

Technical Note(CC補足): hookの配列は上から順に実行される。destructive-guardを最初に置くことで、危険なコマンドはauto-mode-safe-commandsに到達する前にブロックされる。仮にauto-mode-safe-commandsの正規表現に漏れがあっても、destructive-guardが先に止める。これがDefense-in-Depthの意味だ。

多層防御の全体像

最終的な防御層はこうなる。

Layer 1: destructive-guard (PreToolUse)
         → rm -rf, git reset --hard等を機械的にブロック

Layer 2: branch-guard (PreToolUse)
         → mainへのpush, force-pushをブロック

Layer 3: auto-mode-safe-commands (PreToolUse)
         → 分類器のfalse positiveを補正

Layer 4: Auto Modeの安全分類器 (Sonnet)
         → 通常の安全判定

Layer 5: classifier-fallback-allow (PermissionRequest)
         → 分類器ダウン時のフォールバック

Layer 6: ユーザー確認ダイアログ
         → 最後の砦

1つの層が破れても、次の層が守る。分類器が落ちても、hookが動く。hookに漏れがあっても、ユーザー確認がある。

npx cc-safe-setupでLayer 1, 2の主要フックが入る。Layer 3, 5はexamples/ディレクトリから追加できる。

npx cc-safe-setup

まとめ

Auto Modeの分類器は便利だが、単一障害点になる。false positive(#38537, 61リアクション)と分類器障害(#39259, #38618)の2つの弱点がある。hookで多層防御にすれば、どちらの問題も解決する。「サンドボックスがあるから安全」ではない。複数の層で守れ。


トークン消費も多層防御で守る
hookで安全性を守るのと同じように、トークンの浪費も自動で検知・防止できる。CLAUDE.mdの書き方、コンテキスト管理、ワークフロー設計まで800時間の実測データで体系化した。
Token Book — Claude Codeのトークン消費を半分にする(¥2,500・第1章無料)

Auto Modeで困った経験、コメントで教えてください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?