「codex 更新のたびに手動で sha256 を編集するとか、めんどくさすぎでしょ」
筆者がこう打ったのは、AI が出してきた設定手順を読んだときだ。実行ファイルを root 所有の場所へ sudo install で置く行があり、その下に実行ファイルの sha256 を設定に書く行があった。添え書きは「codex を更新したら書き直します」。
セキュリティの相談ではない。ただの愚痴である。ところが AI はこの愚痴を受けて防御の並びを組み直し、sha256 が防ぐはずの攻撃はもう成り立たない、と言い出した。この記事は、AI が足していった防御を、どの問い返しで見直させたかの記録だ。
防御は、指摘の数だけ増える
筆者は、issue から PR、レビューまでを Claude Codeに回させる自作の開発自動化フローを使っている。その security review を、OpenAI の Codex CLI(ChatGPT Plus の $20/月 などの有料プランに含まれる)にも回せるようにした。当初の設計では、Codex は AI の作業場所である sandbox の外で動く。だから、レビューされる側の PR のコード(テストなどで実際に動く)に、Codex の起動を乗っ取らせない仕掛けが要った。
仕掛けは、AI のレビューと修正の往復で固めていった。
始まりは最初の PR のレビューで、major が 2 件出た。どちらも「PR のコードが残したプロセスが sandbox の中に居座り、Codex の作業ファイルを書き換える」という前提の攻撃だった。AI の説明では、これは既存の Claude 側のレビュー経路にも同じ形である前提で、この PR で開いた穴ではない。おすすめは、この PR では受け入れて別 issue で扱うこと。筆者は「major は受け入れて別 issue 化」と返した。
受け入れたはずの指摘は、次の round で戻ってきた。中身は同じで、重大度だけが major から critical に格上げされていた。この前提は、issue の範囲外の欄に最初から書いてあった。それでも戻ってきた。レビュー役が読む指示に書いていない範囲外は、肩書きだけ変えてまた来る。
あとは同じ形の繰り返しだ。レビュー役の AI が攻撃の筋を挙げ、修正役の AI が防御を 1 枚足す。次の round では、足した防御の脇を突く筋が出る。1 本の PR の中だけでも、30 分ほどでこう積み上がった。
| 順 | 塞ぎたい筋 | 足した防御 |
|---|---|---|
| 1 | PATH の手前に偽の codex を置かれる | 設定に書いた絶対パスで起動する |
| 2 | 実体が script だと、中の interpreter を PATH で探しに行く | script を拒否し、ネイティブの実行ファイルだけ通す |
| 3 | 書ける場所に hard link を張って中身を書き換え、link を消して元どおりに見せる | 実体の sha256 を設定の値と照合する |
| 4 | 実体や置き場所を自分の権限で書き換えられる | 自分の所有でなく、他人も書けない場所にだけ置かせる(root 所有) |
1 枚ずつ見れば、どれも筋が通っている。ただ、root 所有のコピーは sudo で置き直す。sha256 は codex を更新するたびに書き直す。防御が 1 枚増えるたびに、人の宿題も 1 行増えた。
「めんどくさすぎでしょ」で、AI は防御の受け持ちを組み直した
冒頭の愚痴に、AI はこう返した。sha256 が想定していたのは、表の 3 行目の攻撃だ。そして 4 行目の条件を満たしていれば、この攻撃はもう成り立たない。
- hard link は同じ実体を指す別名で、権限は実体の側に付いている。どの link から開いても、root 所有で書き込み不可のファイルには書けない。所有者でなければ権限も変えられない
- 祖先のディレクトリも書けないので、パスごと別のファイルに差し替えることもできない
つまり sha256 の照合は、手前の関所(root 所有)が破られたときにしか出番がない。その関所は、破られない作りになっている。
AI は sha256 を「fix の途中で root 所有の条件が足される前に入った防御が残ったものに見えます」と見立てた。commit の履歴を並べると、そのとおりだった。sha256 の照合が入った 8 分後に、所有者の確認が入っている。仕事はもう丸ごと後任のものなのに、前任者は退職届を出さずに居残っていた。
ただし AI は、こう断ってもいた。「外しても安全性は下がらないと判断しています。ただしこれはコードを読んだうえでの判断で、外して試したわけではありません」。取り外しの見積もりは出た。試運転はまだである。
外す前に確かめるなら、その防御が防ぐはずだった攻撃を、残りの防御に向けて実際にやらせる。今回なら次の 2 つだ。
| AI にやらせること | 期待する結果 |
|---|---|
| 攻撃する側と同じ立場(sandbox の中から、同じユーザーで)実体への hard link を作り、その link から書き込む・権限を変える | link が作れない。作れても、書き込みも権限の変更も拒否される |
| 実体の置き場所から / までの、すべての祖先ディレクトリにファイルを作る | どの階層でも作れない |
親だけ見て安心しない。上の階層に 1 つでも書けるディレクトリがあれば、親ごと名前を変えてパスを付け替えられる。
どちらかが通るなら、その 1 枚はまだ仕事をしている。
1 枚では終わらなかった
sha256 が要らないと分かっても、root 所有のコピーを置き直す手間は残る。AI はこれを、設定管理の仕組みに毎回コピーさせて自動にする案を出してきた。手作業は消える。代わりに、防御を支える仕組みがもう 1 つ増える。
そして sha256 の愚痴から 1 時間ほどで、守る要件と境界を先に決め直す修正が入った。sandbox に居座った同じ権限のプロセスによる攻撃は境界の外として、重大な指摘にさせないようレビュー役の指示に書き、人に手作業を課す修正もさせないようにした。Codex は sandbox の中で動かす前提に変え、境界の外を守っていた検査をまとめて外した。sha256 も root 所有の確認も、その中に入っている。境界の外の例としてレビュー役の指示に並んだのは、hard link や名前の付け替えによる入れ替え、PATH の手前に置いた同名の実行ファイル。表の 4 行の攻撃が、ほぼそのまま名簿に載った。この修正で消した行は、足した行のおよそ 5 倍だった。1 枚外す相談のはずが、気付けば解体工事になっていた。
「それ、on になってる?」
境界の修正の後、自動化フローの別の入口から起動したレビューでも Codex を効かせる PR を merge した。そこで筆者が聞いた。
「codex 使う設定って on になってる?」
AI が設定を読む順に見ていくと、どこにも書かれていなかった。既定の Claude 側の経路で動いていて、merge したばかりの PR の security review も Claude が回していた。何重にも鍵を掛けて守っていた扉は、実際は開けてすらいなかった。
自分ならどこで問い返すか
| タイミング | 問い | 出てきたもの |
|---|---|---|
| レビューが新しい攻撃の筋を挙げたとき | 「この PR で開いた穴? 前からある前提?」 | 今回は AI が先に出した。前からある前提なら、受け入れて別 issue に。境界としてレビュー役の指示にも書かせる |
| 防御のせいで手作業が増えたとき | 「〜とかめんどくさすぎでしょ」 | 各防御が何を防ぐかの組み直しと、重複した 1 枚 |
| AI が「外しても安全」と言ったとき | 「その攻撃、残りの防御に向けて実際にやってみて」 | 今回は聞いていない。外す前の確かめは、読みではなく実行で |
| merge した後 | 「それ、on になってる?」 | 設定がどこにも無く、既定のまま |
1 行目は、筆者が聞く前に AI のほうから言ってきた。この行は、筆者の手柄ではない。3 行目は、筆者が今回聞きそびれた問いだ。境界ごと決め直して検査をまとめて外したので出番は無かったが、1 枚だけ外す場面なら、ここが抜けていた。
まとめ
AI に security の指摘を直させると、防御は 1 枚ずつ足されていく。面倒だと感じたら、遠慮せずそのまま伝えていい。AI が各防御の受け持ちを組み直し、重複を見つけてくる。ただし「外しても安全」はコードを読んだ判断なので、外す前に攻撃を実際にやらせて確かめる。同じ前提の指摘が繰り返し出るなら、防御を足す前に守る境界を決めさせる。愚痴は、立派な見直しの入口になる。
AI エージェントに開発やレビューを任せる組み立ては、AI実装支援でも相談を受けている。1 本ずつ正しい修正が同じ場所に積み上がる話は、バグ修正を根本原因から直させる記事にまとめた。



