AnthropicがAuto Modeの安全設計について公式記事を公開した。
核心的なデータ: ユーザーは確認プロンプトの93%を承認している。つまり大多数のプロンプトは不要で、承認疲れを引き起こしている。Auto Modeはこれを安全分類器(Sonnet 4.6ベース)で自動化する。
だが「Auto Modeを有効にすれば安全」という理解は危険だ。公式記事自体が「careful human reviewの代替ではない」と明記している。分類器には2つの弱点がある。
-
誤検出(false positive): 安全なコマンドを「要確認」と判定する。
$()を含むコマンド、パイプチェーン、複合コマンドが頻繁に引っかかる -
分類器障害: Sonnetのインフラが落ちると、全てのコマンドが「要確認」になる。
catもlsも手動承認が必要になる
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) → 安全 → 実行
→ 要確認 → ユーザーに確認
分類器は読み取り専用コマンド(ls、cat、grep等)を自動で許可し、破壊的コマンド(rm、git 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 # 複合コマンド
mkdirもcat | grepもcd && 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つの役割がある。
- PreToolUse hook(auto-mode-safe-commands): 分類器のfalse positiveを補正する。安全なコマンドを自動許可する
- 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はスルー → ユーザーに確認 |
重要なのは、危険なコマンドは誰も自動許可しないこと。rm、git push --force、DROP 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で困った経験、コメントで教えてください。