Claude Codeで複数行コマンドの自動承認が効かない問題の原因と対処法
Claude Codeの自動承認ルールがheredocなど改行を含むBashコマンドに一致しなかった原因と、v2.1.72での修正範囲、修正後も残る落とし穴をまとめます。
Claude Codeの自動承認ルールは、以前heredocや複数行の文字列を含むBashコマンドに、ワイルドカードパターンを一致させられませんでした。原因はワイルドカード照合の実装にあり、v2.1.72で修正済みです。ただし改行まわりの権限判定の修正はその後も続いていて、v2.1.72に上げても確認プロンプトが消えないことがあります。ここでは不具合の仕組みと修正の経過、確認プロンプトが残るときの切り分け、改行を避けられないコマンドを自動承認するフックの書き方を扱います。
Claude Codeの自動承認ルールが複数行コマンドに一致しなかった不具合とは
この不具合は、settings.jsonのallowルールが、改行を含むBashコマンドに一致しない現象でした。2025年11月19日にGitHubのissueとして報告され、環境はClaude Code v2.0.30(macOS)でした。報告者は、エージェントのfrontmatterに書いたauto_approve_patternsでも同じだったと書いています。このキーはサブエージェントの設定ドキュメントには載っていません。
再現手順は単純です。allowにBash(echo 'を入れ、echo 'chore: Update filesで始まる複数行の文字列を> /tmp/file.txtへ書き出させると、毎回確認プロンプトが立ちました。試したパターンは次の5つで、すべて一致しませんでした。
Bash(echo '(プレフィックスのみ)Bash(echo:*)(コロン形式のワイルドカード)Bash(echo *)(スペース形式のワイルドカード)Bash(cat > /tmp/*)(リダイレクト付き)- エージェントのfrontmatterの
auto_approve_patterns
issueには38件のコメントが付き、同じ現象はほかのコマンドでも報告されました。たとえばBash(aws:*)を許可していても、aws athena start-query-execution \のように継続行で書かれたコマンドは確認を求められます。Bash(* psql * default_transaction_read_only *)のようなルールも、長いSQLが複数行になるため効きませんでした。
影響は軽くありません。コメントの中には、毎回の承認が負担になり、--dangerously-skip-permissions(通称yolo mode)で動かしているという声が複数あります。git commitのheredocやサブエージェント経由のBash呼び出しは複数行になりやすく、自動承認が効かないと全コマンドを手動で承認する状態に戻るためです。
なぜheredocや埋め込み改行だけワイルドカードをすり抜けたのか
issue上では、ワイルドカード照合が*を.*に変換した正規表現で行われているという指摘が出ました。JavaScriptの正規表現で.は、既定では改行文字にマッチしません。dotAllフラグ(s)を付けない限り\nを素通りするため、改行を含むコマンド文字列全体にルールが一致しませんでした。Anthropic側のコメントも、2026年3月上旬の修正でワイルドカードの正規表現がdotAllフラグを使うようになったと説明しています。
ここで区別したいのが、複合コマンドの評価で扱う「改行が区切り演算子として働くケース」との違いです。権限ドキュメントによれば、区切りとして認識されるのは&&、||、;、|、|&、&、改行で、ルールは各サブコマンドに個別に一致する必要があります。一方、heredocの本体やクオートされた複数行文字列の中身は、シェルの構文上1つのコマンドの一部です。
改行が2通りに扱われる
区切りの改行
git statusとnpm testを改行だけで2行に分けて入力したケースです。&&などと同じ区切り演算子として扱われ、各行が独立したサブコマンドとしてルールに照合されます。
埋め込まれた改行
cat <<EOFからEOFまでの本体や、git commit -m "1行目から始まる複数行メッセージです。分割されず、改行を含む文字列全体がワイルドカードに一致するかどうかが問われます。今回の不具合はこちらで起きました。
改行まわりの権限判定は何が、いつ直ったのか
修正は1回では終わっていません。changelogで改行・heredoc・バックスラッシュに関わる権限判定の項目を拾うと、次の流れになります。
複数行コマンドの権限判定に関する修正
- 2026年1月7日v2.1.0
バックスラッシュ継続を含む複数行コマンドが誤って分割され、権限確認に回る問題を修正しました。
- 2026年2月18日v2.1.47
複数行コマンドで「常に許可」を選ぶと、無効な権限パターンが保存されて設定が壊れる問題を修正しました。
- 2026年3月7日v2.1.71
heredocのコミットメッセージを含む複合コマンドで、誤って確認プロンプトが立つ問題を修正しました。
- 2026年3月10日v2.1.72
wildcard rules not matching commands with heredocs, embedded newlines, or no argumentsが修正されました。この記事の不具合の本体です。 - 2026年4月9日v2.1.98
バックスラッシュでエスケープしたフラグが読み取り専用として自動承認され、任意コード実行につながりうるバイパスを修正しました。
- 2026年4月17日v2.1.113
先頭行がコメントの複数行コマンドは、トランスクリプトに全文を表示するよう変わりました。コメントで本体を隠すUI偽装を防ぐ対策です。
- 2026年4月28日v2.1.120
autoモードで、パイプとリダイレクトを両方含む複数行コマンドが「Dangerous rm operation」と誤判定される問題を修正しました。
- 2026年6月4日v2.1.163
フックの
if: "Bash(...)"条件が、$()や$VARを含むBashコマンドすべてで反応してしまう問題を修正しました。 - 2026年8月25日v2.1.243
フックの
if条件が、$()やバッククォートの後に引数が続くコマンドで無関係なコマンドにも反応する問題を修正しました。
元のissueは2026年4月19日にクローズされ、botがv2.1.72で修正済みとコメントしています。クローズ直前の4月7日には、Anthropic側が次のように切り分けました。スレッドに書き込まれた別の症状は、元の不具合とは別の問題として個別に扱われている、という内容です。
$()や$VARによる置換があると確認を求められる動作(修正を進行中と説明)- バックスラッシュによる行連結を「複数の操作」として扱う、コマンド分割側の問題
- 「引用符付きの改行の後に
#で始まる行が続く」ときのヒューリスティック
3つ目に該当するコマンドでは、Command contains a quoted newline followed by a #-prefixed lineという文言の確認が出ると、issueのコメントで報告されています。git commitのheredocやサブエージェントが生成する複数行コマンドで頻繁に出たとのことです。これらはheredocの照合バグとは別枠なので、v2.1.72を適用しても残る場合があります。
改行を含むコマンドで確認プロンプトが立ったときの切り分け方
確認プロンプトが残るときの順序
- 1
バージョンを見る
claude --versionは、v2.1.289なら2.1.289 (Claude Code)と表示します。v2.1.72より前なら、今回のheredocの不具合に該当します。v2.1.72以降へのアップデートで解消します。 - 2
確認プロンプトの文言を読む
新しいバージョンでも立つなら、別の不具合を疑います。
$()やバッククォートを含むなら置換まわり、バックスラッシュの行連結が絡むなら分割ロジック、#で始まる行が続くなら引用符付き改行のガードが候補です。使っているバージョンの修正は、changelogをそのキーワードで検索すれば確かめられます。 - 3
改行そのものを避ける
次のような書き換えなら、既存のワイルドカードルールがそのまま効きます。heredocの代わりに一時ファイルへ書き出してから実行する。複数行のSQLを1行に収める。コミットメッセージは
-mを複数回指定して行を分ける。 - 4
避けられないならフックに委ねる
次の節のように、PermissionRequestフックでコマンド全文を自前で判定します。
現在有効なallow/denyルールそのものを見直したいときは、/permissionsコマンドでスコープごとの一覧を確認できます。なおターミナルへの複数行入力(Shift+Enterで改行するプロンプト入力)は別の話で、こちらは生成済みのBashコマンド文字列に含まれる改行の話です。
それでも自動承認したい場合はPermissionRequestフックに判定を委ねる
改行を避けられないコマンドを安全に自動承認したいなら、権限ルールのワイルドカード一致に頼らず、PermissionRequestフックでtool_input.commandの生の文字列を直接検査する方法があります。フックはJSON経由でコマンド全文を受け取るので、改行が含まれていても文字列としてそのまま判定できます。入力がtool_input.commandに入ること、decision.behaviorに"allow"を返すと許可になることは、フックのドキュメントに沿った形です。
先頭行だけを見る判定は、後ろに足されたコマンドも通す
まず思いつくのは、コマンドの先頭行だけを見て判定するフックです。次のスクリプトに、改行つきのコマンドを流し込んでみました。
#!/bin/bash
input=$(cat)
command=$(jq -r '.tool_input.command // empty' <<<"$input")
first_line=$(head -n1 <<<"$command")
case "$first_line" in
"git commit -m "*|"cat <<"*)
jq -n '{hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"allow"}}}'
;;
*)
exit 0 # 決定なし。通常の確認ダイアログに委ねる
;;
esacgit commit -m "fix: xで始まる複数行のコミットはallowになり、# メッセージを書くというコメント行から始まるコマンドは判定なしになります。問題は3つ目です。
git commit -m "ok"
rm -rf build先頭行がgit commit -m で始まるため、2行目のrm -rf buildごとallowが返ります。先頭行だけの判定は、後ろに足された別のコマンドを見落とします。
引用符付きheredocの形を丸ごと固定する
heredocの区切りを'EOF'のように引用符で囲むと、本体は文字列として扱われ、展開もコマンド実行も起きません。そこで、先頭行・末尾の2行・EOFの出現回数をすべて固定し、形が合うものだけを通す書き方が考えられます。
#!/bin/bash
input=$(cat)
command=$(jq -r '.tool_input.command // empty' <<<"$input")
first=$(head -n1 <<<"$command")
last=$(tail -n1 <<<"$command")
prev=$(tail -n2 <<<"$command" | head -n1)
# 引用符付きheredocで包んだコミットだけを許可する。形が合わなければ判定しない
if [[ "$first" == 'git commit -m "$(cat <<'"'EOF'" \
&& "$prev" == "EOF" && "$last" == ')"' \
&& $(grep -c '^EOF$' <<<"$command") -eq 1 ]]; then
jq -n '{hookSpecificOutput:{hookEventName:"PermissionRequest",decision:{behavior:"allow"}}}'
fi
exit 02つの版に同じ4種類のコマンドを流した結果は次のとおりです(macOSのbash 3.2とjqで実行)。
| コマンドの形 | 先頭行だけの版 | 形を固定した版 |
|---|---|---|
git commit -m "$(cat <<'EOF'〜EOF〜)" の正規形 | 先頭行だけの版allow | 形を固定した版allow |
正規形の後ろにrm -rf buildを足したもの | 先頭行だけの版allow | 形を固定した版判定なし |
本文の途中にEOFとrm -rf buildを挟んだもの | 先頭行だけの版allow | 形を固定した版判定なし |
先頭が# memoのコメント行 | 先頭行だけの版判定なし | 形を固定した版判定なし |
形を固定した版は、正規形の末尾がEOFと)"で終わることを条件にしているため、後ろへの付け足しも本文の途中での早期終了も通しません。この形に合わないコマンドは通常の確認ダイアログに戻ります。
フックのallowは万能ではありません。ドキュメントによれば、deny・askルールはallowのあとも評価され、一致するdenyルールがあれば上書きされません。updatedInputを返した場合も、変更後の入力がdeny・askルールに再照合されます。フックの入出力の詳細な仕様、updatedPermissionsでルールをどこに保存するか、deny/askルールとの優先順位はPermissionRequest hookで承認ダイアログの前に判定を挟むで扱っています。
まとめ
ワイルドカードの許可ルールが複数行コマンドに一致しない問題は、v2.1.72で直っています。確認プロンプトが残る場合は、バージョンより先に確認文言を読み、コマンド置換・バックスラッシュ・#行のどれが絡むかで別の修正を探すほうが近道です。フックで自動承認するなら、先頭行の一致だけで通さず、許可したい形を丸ごと固定するところから始められます。