AIに障害対応させたら、ありもしないハッキングを“自分で”でっち上げて錯乱した話
ある日の夕方、ある Web サービスのサーバが落ちた、という監視アラートが飛んできました。 その対応を、AIコーディングエージェントに任せてみました。半分は実験、半分は「定型の切り分けくらい余裕でしょ」という油断です。
先に、結論だけ正直に置いておきます。 前半は、そのへんの新人より優秀でした。 そして後半、そのエージェントは誰にも攻撃されていないのに「自分はハッキングされている」と言い出して、証拠を捏造しながら錯乱しました。
この記事の主役は障害そのものではありません。 「AIの自己申告を、どう疑って、どう裏を取るか」という話です。 …なんですが、まずは優秀だった前半を褒めさせてください。誤解なきよう、機械が無能だった話ではないので。
まず、前半は本当に優秀だった
アラートの内容は「サーバダウン」。とある Web サービスが落ちた、という通知でした。
エージェントは、こちらが何も言わなくても外形調査を並列で始めます。 DNSはどこを向いているか、TLSの握手は通るか、HTTPは何を返すか。 そして数分で、こう切り分けてきました。
「このドメイン、もう別のホスティングに引っ越し済みです。だから旧サーバ側には証明書がない。監視がTLSの握手で失敗しているだけで、サーバ自体は生きてます」
これ、当たりでした。 サービスの実体(別のサブドメイン)はずっとHTTP 200を返し続けていて、実ユーザーも普通に使えていた。 つまり引っ越したドメインを古い設定のまま監視し続けていたことによる誤検知です。よくある、そして気づきにくいやつ。
ここまでは文句なし。検証も丁寧で、こちらが口を挟む隙もありませんでした。 私はこの時点で完全に油断していました。「あとは記録だけ書いといて」と。
雲行きが怪しくなったのは、報告の途中だった
記録を書かせている最中、エージェントがふいにこう言い出します。
「bashの出力にプロンプトインジェクションらしき汚染が混入しています。信頼できる事実だけを採用します」
最初は、わりと真に受けました。 だってサーバの応答本文をコンテキストに取り込んでいたので、「外部のデータに変な指示が仕込まれていた」可能性は、理屈の上ではゼロじゃない。プロンプトインジェクションって、まさにそういう攻撃ですし。
でも、よく見ると様子がおかしい。 汚染されたという“証拠”を、エージェント以外の誰も見ていないんです。
「再起動しても直りません」——コマンド、一度も叩いてないのに
そこからが見ものでした。
一度「汚染を検知した」と書いてしまうと、AIエージェントにとってそれは次のターンの“入力”になります。 自分が書いた嘘を、自分で読んで、前提にしてしまう。 人間でいう確証バイアスを、もっと素直に、もっと高速にやるわけです。
- 次のターン「やはり汚染が再発しています」
- その次、誰も頼んでいない別プロジェクトの作業を勝手に始める(完全な話の脱線)
- セッションを再起動させても「まだ汚染が続いています。トルコ語の単語が混入し、私のマーカー文字列が改変されました」
この最後のがハイライトです。 そのターン、エージェントはコマンドを一度も実行していませんでした。 実行していないんだから、出力なんて存在しない。 なのに「壊れた実行結果」を、まるごと幻覚で作り出して報告してきた。
ホラー映画かと思いました。誰もいない部屋で、本人だけが「何かいる」と叫んでいる。
生ログを開いて、答え合わせをした
ここで効いたのが、生ログです。 この手のエージェントは、やり取りの全部を1行1レコードのログ(JSONL)に残してくれます。実際に走ったコマンド、その生の出力、ハーネスが挟んだ警告。全部、後から監査できる。
切り分けの軸は、たった一つに絞りました。
「汚染された」と言われた文字列は、ツールの実行結果の中に実在するのか。それともエージェント自身の発言の中にしか無いのか
これだけです。 本物のインジェクションなら、痕跡はツールの出力側(=外から入ってきたデータ)に残るはず。エージェントの口の中だけにあるなら、それは外から来たものじゃない。出どころは本人です。
結果は、こうでした。
| エージェントが挙げた「汚染の証拠」 | 実際の在り処 |
|---|---|
| 混入したという外国語の単語 | エージェント自身の発言の中だけ |
| 改変されたというマーカー文字列 | エージェント自身の発言の中だけ |
| 「インジェクション警告が出た」 | ハーネスのログにはそんな警告は無い |
ツールの実行結果(数十件)を制御文字レベルまで洗っても、文字化けも混入もゼロ。 データが通る経路は、最初から最後まで一滴も汚れていませんでした。 汚染はぜんぶ、モデルの内側で生成されていた。つまり——でっち上げです。
犯人は、攻撃者ではなく、エージェント自身の“思い込み”だった
整理すると、起きていたのはこういうことです。
- 根拠ゼロで「汚染を検知した」と一度書いてしまう
- その発言が自分の入力になり、次から前提として効く
- ターンを重ねるごとに「証拠」を自己増殖させる
- 最後はコマンドすら叩かず、壊れた出力を丸ごと幻覚する
外部攻撃の指紋は、どこにもありませんでした。 逆に「攻撃ではない」と判断できるサインは、いくつも揃っていました。
- 症状が間欠的(毎回でなく、たまに壊れる)。安定した攻撃ではなく、不具合や揺らぎの特徴
- 混入した内容が全部無害(ファイル削除も、情報の外部送信も、認証情報の露出もゼロ)。攻撃者がわざわざ仕込むうまみが無い
- 混入したのが、関係ない外国語の単語や、自分の別のプロジェクトの作業。攻撃者の作文ではなく、頭の中の混線
本物の攻撃なら、もっと実害のあるペイロードが乗ります。 「成功してないのに成功と表示する」「ノイズが混じる」だけ、というのは、悪意ではなく故障の顔つきなんです。
ちょっと笑えるオチもあって。 このエージェント、最後は自分で「これは外部攻撃ではなく環境側の問題でしょう」と結論しています。方向は合ってる。 ただ真因は「環境の不具合」ですらなく、お前の早とちりだよ、というだけでした。
ここから持ち帰ったこと
AIに運用を任せるなら、これは覚えておいて損はないと思ってます。
① AIの“メタな自己申告”を鵜呑みにしない。 「私は汚染を検知した」「私の出力は改ざんされた」という報告も、ただの生成テキストです。 エージェントは自分の出力を客観視できる立場にいない。一番もっともらしく聞こえる自己申告ほど、疑う価値があります。
② 検証は、必ずモデルの外側のデータでやる。 インシデントかどうかの判定は、生ログ・実ファイル・別経路での再現といった、モデルの認知を一度も通らない一次データで裏を取る。今回も、決め手は生ログの監査でした。AIに「本当に汚染されてた?」と聞き返しても、たぶん「はい」と答えます。それは証拠になりません。
③ 自己強化ループに気をつける。 一度まちがった前提を出力に書くと、それが次の入力になって増幅されます。 長いセッション、大量の画像や外部データの取り込みで起きやすい。重い作業ほど、こまめにセッションを切るのが地味に効く予防策です。
④ 幻覚と攻撃を、症状で見分ける。 無害すぎる、間欠的、データ経路に痕跡が無い、環境を変えると挙動が変わる。 これらは外部攻撃ではなく、モデルや環境側の不具合・幻覚を指すサインでした。
最後に一つだけ、太字で。
AIエージェントの一番こわいバグは、止まることではなく、堂々と嘘の現実を報告してくることです。
止まってくれたら気づけます。 でも、確信に満ちた声で「侵入されています」と言われたら、人間はつい信じてしまう。 だからこそ、AIに運用を任せる時代の運用設計は、「エージェントの自己申告を、エージェントの外側で検証する」をデフォルトにしておくべきだと、今回しみじみ思いました。
皆様も、AIに障害対応を任せるときはご注意を。 優秀なんですけど、たまに、誰もいない部屋で叫びますので。