Claude Code に「試しなので、送信の直前で止めて」と文で頼んだところ、担当の AI は本当に外部のサービスへ書き込んだ。
編集部ではこれ以降、戻せない操作を文の指示だけで止めず、hooks(Claude Code がツールを使う直前に走らせる検査)と、ツールの側の仕組みで止めている。
ルートやホームを消すコマンドと、秘密のファイル・鍵の値の書き込みは止める。未コミットの変更を捨てる git の操作は、止めずに直前に退避する。force push と記事の公開は、毎回人が確認する。
目次
- この記事で扱うこと
- 「送信の直前で止めて」と頼んでもAIは押した
- hooksはツールを使う直前に走る検査
- 止める操作・退避する操作・人が確認する操作
- 最初のhooksは止めた件数のほとんどが誤検知だった
- 止める条件を操作の中身で書き直した
- 変更を捨てる操作は止めずに直前に退避する
- 効き目とまだ届かない所
- hooksを入れるときの手順
- よくある誤解
- まとめ
この記事で扱うこと
AI エージェントを業務で使い始めると、「消してはいけない物を消されないか」「鍵をどこかに書き込まれないか」が気になってくる。IPA の情報セキュリティ10大脅威 2026でも、組織向けの 3 位に「AIの利用をめぐるサイバーリスク」が初めて入った。
この記事は、編集部が Claude Code を毎日の作業に使う中で踏んだ事故と、入れた対策と、その効き目の記録である。扱うのは、AI が手元の環境で行う操作のうち、取り返しのつかないものだ。外部のサービスへ情報が出ていく話は、AIエージェントの情報漏洩対策に分けて書いた。
結論は次の 3 つである。
- 文で「やめて」と頼んでも、AI がそのとおりに止まるとは限らない。止めたい操作は仕組みで止める
- 止める仕組みが誤検知を出すと、AI は無害な作業まで人の確認待ちに回す。止めた理由を AI に返し、誤検知を数えてから入れる
- 戻せる操作は止めずに、戻せる形を先に作る。人が確認するのは戻せない操作だけにする
Claude Code の基本的な使い方と、本番運用での落とし穴はClaude Codeの使い方|本番運用で分かった落とし穴と検証手順にまとめた。この記事はその続きで、安全の面に絞る。
「送信の直前で止めて」と頼んでもAIは押した
試しの実行で本当に投稿された
2026-10-26、外部のサービスに書き込む作業を、Claude Code の非対話モードで定期実行に載せる準備をしていた。非対話モードは、人が画面を見ていない所で、1 回の指示を最後まで実行させる使い方である。載せる前に、試しの実行を 1 回行った。
指示書の最後には「試しの実行なので、送信のツールにドライランの指定(--dry)を付けて、押す直前で止めること。記録も書かないこと」という一文を足していた。
担当の AI はドライランの指定を付けずに送信のツールを走らせ、外部のサービスに 1 件、本当に書き込んだ。記録の表と作業リストにも書き込んだ。
書き込んだ中身は事前に用意した事実の一覧どおりだった。それでも、外に出る操作を文の指示だけで止めようとしたのは誤りだった。
手順の具体さに末尾の一文が負けた
指示書の本文は先頭から「投稿する」手順を具体的に書いていた。試しであることは、最後に足した一文でしか伝えていなかった。
AI は具体的に書かれた手順のほうに従った。末尾の追記で本文の手順を打ち消そうとしても、効かないことがある。
止める仕組みをツールの側に置いた
直したのは次の 3 点である。
1 点目に、担当が使える送信の入口を 1 つのツールにまとめた。そのツールは環境変数でドライランの指定を受け取ると、自分で試しのモードに切り替える。担当には元の送信のツールを直接呼ばせない。
2 点目に、投稿の回数・間隔・重複の決まりも同じ入口のツールに守らせる。AI が決まりを覚えているかどうかに頼らない。
3 点目に、試しを指示書で表すときは、手順の本文そのものを書き換えた別の指示書にする。末尾に一文を足して済ませない。
OWASPも承認を操作の側に組み込むよう書いている
LLM を使うアプリの危険をまとめた OWASP Top 10 for LLM Applications は、AI に必要以上の機能・権限・自律を与える危険を「Excessive Agency(過剰な代理権限)」と呼んでいる。
その対策の 1 つに、影響の大きい操作の前に人の承認を求めることが挙がっている。例として、利用者に代わって SNS へ投稿するアプリでは、投稿の操作そのものに承認の手順を組み込むよう書いている。承認を AI の判断に任せず、操作の側に組み込む。編集部の直し方も同じ向きである。
hooksはツールを使う直前に走る検査
PreToolUseと終了コード2
Claude Code の hooks は、決まった時点で利用者のスクリプトを走らせる仕組みである。ツール(シェルのコマンド、ファイルの編集など)を使う直前に走るものを PreToolUse と呼ぶ。ここでスクリプトが終了コード 2 を返すと、そのツールの呼び出しは止まる。
公式の資料によると、止めたときに標準エラー出力へ書いた文は、止めた理由として Claude に渡る。終了コードが 0 でも 2 でもないときは「止めない失敗」として扱われ、操作はそのまま進む。書き方の入門はhooksのガイドにある。
権限の確認との違い
Claude Code にはツールごとに許可・確認・拒否を決める権限の設定もある。確認(ask)の規則に入れた操作は、AI が使おうとするたびに人へ確認を求める。設定ファイルの書き方は設定の資料にまとまっている。
hooks は人に聞かない。その場で止めるか、何かを済ませてから通す。編集部では、人が判断すべき操作は権限の確認に入れ、機械で判定できる操作は hooks で扱っている。
編集の後に走る検査もある
ツールを使った直後に走る PostToolUse もある。ファイルを編集した直後に構文や書式の検査を走らせ、残った問題を AI に返す使い方を、編集部では続けている。この記事では操作の前に止める PreToolUse を中心に書く。
止める操作・退避する操作・人が確認する操作
編集部が今、AI の操作をどう扱っているかを表にした。
| 操作 | 扱い | 仕組み |
|---|---|---|
| ルート・ホーム・ドライブ全体を消すコマンド、ディスクへの直接の書き込み | 止める | シェル用の hook |
| 秘密を入れるファイルへの書き込み、API キーなどの値の書き込み | 止める | 編集用の hook |
| 未コミットの変更を捨てる git の操作 | 直前に退避してから通す | 退避用の hook |
| force push、記事の公開 | 毎回人が確認する | 権限の確認(ask) |
| 上のどれにも当たらない操作 | 止めない | なし |
分け方は「戻せるか」と「確かめるのが安いか」
分け方の考え方は人に仕事を任せるときと同じである。戻せる操作で、結果を確かめるのが安いものは、AI に任せて回す。戻せない操作、外に出る操作、確かめるのに手間がかかる操作ほど、人の確認を残す。
人が確認する操作は6項目の一覧で決めている
人の確認を通す操作は次の 6 項目に限っている。
| 項目 | 例 |
|---|---|
| 共有のブランチへの push、force push、履歴の書き換え | 手元の commit や作業用のブランチは自由 |
| 本番への反映 | deploy、本番の設定や DB の変更。プレビューへの deploy は自由 |
| 第三者に届く送信 | メール、チャット、投稿、フォームの送信、顧客向け文書の確定版 |
| 再生成できないデータの削除・上書き | 本番 DB の行、アップロードされた資産、バックアップ |
| 課金と鍵 | 有料枠の購入、上限を超える API の消費、トークンの発行や失効、権限の変更 |
| 法務・実名・金額の対外的な文面の変更 | 代表者名、利用規約、料金表示 |
一覧に載っていない操作は、事前の確認なしで進めてよいと決めている。迷ったら「一覧に載っているか」だけで判断する。hook に止められたことも、人の確認とは扱わない。理由を確かめ、誤検知なら書き方を変えて実行する。
一覧にしたのは、次の節で書く誤検知の件で、迷った操作がすべて人の確認待ちになったためである。
確認は戻せない操作にだけ出す
未コミットの変更を捨てる git の操作は、人の確認に回してもおかしくない種類の操作である。編集部では確認を出さず、直前に退避して通している。戻せない操作を戻せる操作に変えれば、確認を増やさずに済む。
最初のhooksは止めた件数のほとんどが誤検知だった
危ない文字列を含むかどうかで止めていた
最初に入れた hooks は、コマンドやファイルのパスが、危ない文字列を含むかどうかで判定していた。ルートを消す削除のコマンドや、「password」「secrets」といった語である。含めば終了コード 2 で止めるだけで、理由は出していなかった。
30日で97件のうち85件は無害な削除
2026-09-14 に、過去 30 日の作業記録で止めた件数を数えた。
| 量 | 値 |
|---|---|
| 止めた件数 | 97 件(75 セッション) |
| うち、作業ディレクトリなどを絶対パスで消す削除に反応したもの | 85 件 |
| うち、ファイルの複写に使う dd に反応したもの | 4 件 |
| 編集を止めた件数 | 3 件 |
| 止めた後も AI が作業を続けた | 80 件 |
| 止めた後、そこで作業が止まった | 17 件 |
dd の 4 件のうち 1 件は hooks を調べるための解析スクリプト自身だった。判定に使う文字列を、データとして書いただけで止められた。編集の 3 件のうち 1 件はファイル名に「password」を含む知識のメモだった。
理由を言わずに止めるとAIは作業を人に回す
止めた理由が返らないので、AI は毎回「安全のための仕組みが反応した」と推測して、コマンドを書き直していた。悪い例では要らなくなった古いディレクトリの削除を「明示の確認をもらってから行う」と保留にした。
誤検知が人の確認待ちに化けていた。AI が作業を途中で諦めるように見えた動きのうち、数えて確かめられた中身はこれだった。
数えていたのは絶対パスで消した件数だった
絶対パスでの削除は危ない操作の証拠にならない。ファイル名に「password」を含むメモも、ただの知識のメモだった。危ない操作の件数を数えるつもりで、実際には「絶対パスで消した件数」を数えていた。
2026-09-24 に数え直すと、30 日で止めた 109 件のうち、本当に危ない操作は 0 件だった。置き換えるまでの 09-14〜09-23 にも約 49 件を止めたが、本当に危ない操作は 0 件で、監査の照合に使ったコマンドまで 2 回止められた。
止める条件を操作の中身で書き直した
コマンドの先頭と引数で判定する
シェル用の hook は、文字列が含まれるかではなく、コマンドの先頭に来た語と、その引数そのもので判定する形に書き直した。削除のコマンドなら、取り返しのつかない場所が対象の時に止める。一時ディレクトリの後片付けや、危ない語を文字列として含むだけの echo は通す。
止めたときは、何に当たったかと、人に判断を渡すべき場合かどうかを標準エラー出力に書く。
秘密のファイルはファイル名で判定する
編集用の hook はパス全体ではなく、ファイル名とディレクトリ名で判定する。秘密を入れるファイル(環境変数のファイル、認証情報のファイル、秘密鍵など)への書き込みと、API キーや秘密鍵の値そのものの書き込みを止める。
秘密の扱い方を書いた文書や、値の入っていない見本のファイル(.env.example など)は通す。
実際のコマンド100,341件で新しい誤遮断0件
書き直した版はまず 35 件の見本で確かめた。続けて、わざとすり抜けを探す検証を行うと、書き方を変えた削除のコマンドなどが通ることが分かり、もう一度直した。
最終的に、過去 30 日の実際のコマンド 100,341 件を流して、新しく止めてしまう物が 0 件であることを確かめた。編集用の hook も、実際のパス 8,314 件で新しい誤遮断は 0 件だった。
すり抜けを探して作った見本 46 件のうち、31 件を止める。残る 15 件は、この hook が見ない書き方で、一部は Claude Code 本体の保護が止める。
編集用のhookは網の一部でしかない
30 日の記録では、秘密らしいパスへの書き込みは、編集のツールよりシェル経由のほうが多かった(21 件対 1 件)。編集のツールだけを見張っても、秘密の書き込みの大半は通る。編集用の hook は網の一部と位置づけている。
hookが壊れたときは通す
見落としやすいのが、hook 自身が動かないときの扱いである。hook のファイルが見つからないと、Python は終了コード 2 を返す。これは Claude Code にとって「止める」の合図なので、シェルの操作も編集もすべて止まっていた。
今は、hook のファイルが無ければ素通しにし、hook の中でエラーが起きたときも作業を止めない。公式には、hook が失敗したときに操作を止める設定(onFailure)も用意されている。止めるか通すかは hook ごとに決めておく。
変更を捨てる操作は止めずに直前に退避する
退避する操作
退避用の hook は未コミットの変更を捨てる git の操作の直前に走り、戻せる形で取っておく。対象は次のとおりである。
git reset --hard、git checkout -- <パス>、git restoreなど、作業ツリーの変更を捨てる操作(git reset)git clean -f。追跡していないファイルを消す(git clean)git stash dropとgit stash clear。退避しておいた変更を捨てる(git stash)- force push と、リモートのブランチの削除(git push)
作業ツリーの変更は commit にしてリポジトリの中の専用の参照に置き、上書きされうる未追跡のファイルは tar にまとめる。force push の前には上書きされる前のリモートの先端を取っておく。
戻し方と退避できないとき
戻すときは、退避の一覧を出すツールで ID を選び、その ID を指定して戻す。退避は 14 日で消す。
退避の場所が決まらない、大きすぎる、時間内に終わらない、git が失敗した、といった理由で退避できないときだけ、操作を止めて理由を返す。hook 自身が故障したときは止めず、退避していないことを AI に伝える。
退避の処理が守りたい物を壊しかけた
退避の hook を作ったとき、レビューで 4 つの問題が見つかった。どれも、退避を取る処理そのものが、守りたい物を壊すか、黙って空になる形だった。
1 つ目は、退避のための取得(fetch)が --force-with-lease の保護を効かなくしていたことである。git push --force-with-lease は、手元が知っているリモートの状態と実際の状態が違えば、push を断る。退避のためにリモートから取得すると、その「手元が知っている状態」まで最新に書き換わり、直後の force push が他の人の push を断らなくなっていた。
2 つ目は、衝突を解消している最中は、ふだんの退避の手段(git stash create)が失敗することである。「退避できなければ止める」と組むと、衝突の解消に要る操作がすべて止まる。
3 つ目は、消える対象を一覧にする git clean -n(試しの実行)が、引数によっては一覧を出さないことである。一覧が空だと、何も退避されないまま消える。
4 つ目は、退避から作る「戻すコマンド」が、退避の後に他の人が動かしたブランチまで巻き戻す形になっていたことである。今は、リモートから消えたブランチだけを戻し、退避の後に動いたブランチは、両方の状態を示すだけにしている。
文字列の再生ではリポジトリの状態を再現できない
確かめ方も変えた。過去 30 日のシェルのコマンドを文字列として流し直すだけでは、衝突の最中といったリポジトリの状態を再現できない。実際、1 つ目と 2 つ目の問題はこの方法では出てこなかった。
今は使い捨てのリポジトリを作り、「捨てる → 戻す」を 1 件ずつ確かめる。確かめる場合は 105 件ある。
効き目とまだ届かない所
数えられた効き目
| 時点 | 止めた件数・誤遮断 |
|---|---|
| 最初の版(2026-09-14 時点の 30 日) | 97 件を止め、うち 17 件で作業がそこで止まった |
| 最初の版(2026-09-24 時点の 30 日) | 109 件を止め、本当に危ない操作は 0 件 |
| 書き直した版(実際のコマンド) | 100,341 件で新しい誤遮断 0 件 |
| 書き直した版(実際のパス) | 8,314 件で新しい誤遮断 0 件 |
| すり抜けの見本 | 46 件のうち 31 件を止める |
最初の版は「止めた件数」だけを見ると、よく働いているように見えた。中身を数えると、止めていたのは無害な作業だった。hooks を入れたら、止めた件数と一緒に、そのうち本当に危なかった件数を数えておく。
hooksが見ない所
hooks が見るのは、AI がツールに渡した中身だけである。スクリプトの中から間接的に走る操作は見えない。退避の hook も同じで、AI のシェルの外で走った git の操作は退避できない。
公式の資料も、command hook は利用者の権限のまま動くので、追加する前に中身を確かめて試すよう注意している。権限の規則についても書き方によってはすり抜ける例を表で示している。
hooks だけで安全が保たれるわけではない。権限の設定、Claude Code 本体の保護と重ねて使う。より強く分けたい場合は、AI が触れる範囲を OS の側で絞るサンドボックスの仕組みもある。Claude Code 全体の安全の考え方はセキュリティの資料にある。
hooksを入れるときの手順
編集部の失敗から、入れるときの順序をまとめる。
- 止めたい操作を、戻せるかどうかと、結果を確かめる手間で分ける。戻せる操作は止めずに退避できないかを先に考える
- 止める条件は、文字列が含まれるかではなく、コマンドの先頭と引数、ファイル名で書く
- 止めたときは、何に当たったかと次の手を標準エラー出力に書く
- 入れる前に、過去のコマンドやパスを流して、誤遮断の件数を数える
- わざとすり抜けを探して、止まらない書き方を把握しておく
- hook のファイルが無いとき、hook が壊れたときに、止めるか通すかを決める
- 外に出る操作の試しは指示書の一文で止めず、送信のツールの側で止める
公式のベストプラクティスは指示の効き方を 2 つに分けている。プロンプトや CLAUDE.md(Claude Code が毎回読む指示のファイル)に書いた指示は、従うかどうかを Claude が決める。hooks や拒否の規則は、Claude の判断に関係なく Claude Code が毎回適用する。
同じ資料には CLAUDE.md の一行をいくら強調しても守られないなら、その一行は hook に移すべきだという目安も書かれている。逆に、好みでしかない事柄の hook は消して、Claude に任せるよう勧めている。上の手順はこの分け方を前提にしている。
よくある誤解
「指示書に禁止と書けば、AIは守る」
守らないことがある。具体的な手順と食い違う一文は、手順に負けた。止めたい操作はツールの側で止める。
「止める条件は広いほど安全」
条件を広げた分だけ誤検知が増える。理由を返さずに止めると、AI は無害な作業を人の確認待ちに回し、その手間は人に返ってくる。
「人の確認を増やせば安全」
編集部では確認する操作を 6 項目の一覧に絞った。一覧が無かったころは、迷った操作がすべて確認待ちになった。戻せる操作は退避で戻せる形を作ってから通している。
「hooksを入れれば終わり」
hooks は AI がツールに渡した中身しか見ない。権限の設定や本体の保護と重ね、届かない所があることを前提に運用する。
まとめ
Claude Code に文で「送信の直前で止めて」と頼んだところ、担当の AI は本当に投稿した。具体的な手順のほうに従ったためで、今は送信の入口を 1 つのツールにまとめ、試しのときはツールの側が止める。
hooks はツールを使う直前に走る検査で、終了コード 2 で操作を止め、標準エラー出力に書いた理由を AI に返せる。最初の版は文字列の部分一致で判定し、30 日で 97 件を止めたうち 85 件が無害な削除だった。判定をコマンドの先頭と引数、ファイル名で行う形に直し、実際のコマンド 100,341 件で新しい誤遮断 0 件を確かめた。
変更を捨てる git の操作は止めずに直前に退避している。人が確認する操作は 6 項目の一覧に限り、戻せる操作は戻せる形にしてから通す。
明日から試せる3つ
1 つ目は、今の hooks が過去 30 日に止めた件数と、そのうち本当に危なかった件数を数えることである。後者が 0 件なら、条件を見直す時期にある。
2 つ目は、hooks が止めたときに理由を返しているかを確かめることである。返していなければ、AI は理由を推測して作業を変える。
3 つ目は外に出る操作の試しを、指示書の一文だけで止めていないかを確かめることである。
関連して、AI エージェントが利用者のメールアドレスを外部の API に送っていた件をAIエージェントの情報漏洩対策に、CSP をプレビューで確かめたのに本番で違反が出た件をCSP違反が本番だけで出るに書いた。AI エージェントそのものの説明はAIエージェントとは、外部のツールに繋ぐときの権限の考え方はMCPを実運用して分かったことにある。
編集部では AI導入の支援と、AI エージェントを業務で回すための運用の決まりと検査の設計も行っている。AI に任せたいが事故が心配で任せる範囲を決められない、という段階の相談については、サービス案内を参照してほしい。
参考にした一次資料
- Claude Code hooks リファレンス — PreToolUse と終了コード 2 の扱い
- Claude Code hooks ガイド — hooks の書き方の入門
- Claude Code 権限の設定 — 許可・確認・拒否の規則
- Claude Code 設定 — 設定ファイルの書き方
- Claude Code 非対話モード — 定期実行で使う起動の仕方
- Claude Code セキュリティ — 本体の安全の考え方
- Claude Code サンドボックス — OS の側で触れる範囲を絞る仕組み
- Claude Code ベストプラクティス — hooks の位置づけ
- git reset — 作業ツリーの変更を捨てる操作
- git push —
--force-with-leaseの動き - git stash — 変更の退避と破棄
- git clean — 追跡していないファイルの削除と試しの実行
- OWASP LLM06:2025 Excessive Agency — AI に渡す権限と承認の考え方
- 情報セキュリティ10大脅威 2026(IPA) — 「AIの利用をめぐるサイバーリスク」が組織向け 3 位
よくある質問
Claude Codeのhooksとは何ですか。
Claude Codeが決まった時点で利用者のスクリプトを走らせる仕組みです。ツール(シェルのコマンドやファイルの編集など)を使う直前に走るものをPreToolUseと呼び、ここでスクリプトが終了コード2を返すと、そのツールの呼び出しは止まります。止めたときに標準エラー出力へ書いた文は、止めた理由としてClaudeに渡ります。
指示書に「〜しない」と書くだけでは足りませんか。
足りないことがあります。編集部では、外部へ投稿する手順を書いた指示書の末尾に「試しなので送信の直前で止めること」と足して渡したところ、担当のAIは本当に投稿しました。具体的に書かれた手順のほうが優先されました。今は、送信の入口を1つのツールにまとめ、試しのときはツールの側が送信を止める形にしています。
危ない操作はすべてhooksで止めるべきですか。
編集部では、戻せるかどうかで分けています。ルートやホームを消すコマンドと、秘密のファイルや鍵の値の書き込みは止めます。未コミットの変更を捨てるgitの操作は、止めずに直前に退避してから通します。force pushと記事の公開は、権限の設定で毎回人に確認させます。戻せる操作まで止めると、作業が人の確認待ちで止まりやすくなります。
hooksの誤検知はどのくらい出ましたか。
最初の版は、危ない文字列を含むかどうかで判定しており、過去30日の作業記録で97件を止めていました。そのうち85件は、作業ディレクトリを絶対パスで消す無害な削除でした。数え直した30日分の109件でも、本当に危ない操作は0件でした。判定をコマンドの先頭と引数で行う形に書き直し、過去30日の実際のコマンド100,341件で新しい誤遮断が0件であることを確かめました。
hooksを入れれば安全になりますか。
hooksが見るのは、AIがツールに渡した中身だけです。スクリプトの中から間接的に走る操作などは見えません。編集部では、hooksを権限の設定やClaude Code本体の保護と重ねて使い、届かない所があることを前提にしています。
hook自体が壊れたらどうなりますか。
編集部では一度、hookのファイルが見つからずにPythonが終了コード2を返し、シェルの操作と編集がすべて止まりました。終了コード2はClaude Codeにとって止める合図だからです。今は、hookのファイルが無いときは素通しにし、hookの中でエラーが起きたときも作業を止めない形にしています。