AI Security Playbook

解説 / 約20分

AIレビューが合格した。その結果を、どこまで信じていい?

AIに書かせたコードを別のAIにレビューさせ、合格でマージを決めている人へ。1回の合格が保証しないこと、ぶれの確かめ方、確認項目と使い回しのルールを、再現実験の数字で考える。

発展 · AIにコードを書かせ、別のAIのレビューの合格でマージや公開を決めている方へ。

読む前の補足
  • 1回のAIレビューの合格が、何を確かめていないかを説明する。
  • 同じ版に複数回レビューをかけ、結果のぶれを記録する。
  • 自分の現場で出た穴から確認項目を作り、合格を使い回す条件を決める。
  • 1か所直したら、同じ型の箇所を探して記録する。
この記事の目次

AIにログイン機能を書いてもらいました。別のAIにレビューを頼むと、結果は合格(pass)。指摘も直したので、マージして公開する予定です。

ところで、その合格は「欠陥がない」という意味でしょうか。それとも、「今回のレビューが照らした範囲には、止める理由が見つからなかった」という意味でしょうか。

この記事は、AIにコードを書かせ、別のAIにレビューさせて、その合格を公開やマージの判断に使っている個人開発者・小さなチームに向けたものです。PR(変更を取り込むための提案)とレビューの流れを使っている前提で、合格の表示の先にある「何を確かめた結果か」を掘り下げます。

読み終えると、同じ版に複数回レビューをかけて結果のぶれを確かめる方法、自分の現場で出た穴から確認項目を作る方法、合格を使い回してよい条件を決める考え方が分かります。AIレビューをやめる話でも、特定の製品の性能を評価する話でもありません。

AIのレビューの合格で、マージを決める前にその合格は、どこまで照らした結果?

同じ版でも、照らす範囲は回ごとに変わる

AIのレビューは、毎回すべての観点を順番に調べる検査機ではありません。同じコード、同じ依頼文でも、どこに注目して何を書くかは回ごとに変わります。

懐中電灯で暗い部屋を照らす場面に近いかもしれません。ある回はログインの回数制限を照らし、別の回は取り消しの確認漏れも照らす。けれど、どの回も照らさなかった棚がある、ということが起こります。

同じ版・同じ依頼文でも、照らす範囲は回ごとに変わる

  1. ある回のレビュー

    ログイン回数と、データの持ち主を指摘して終わる。

  2. 別の回のレビュー

    同じ2件に加えて、取り消しの確認漏れも指摘する。

  3. どの回も照らさなかった所

    表示のエスケープ、今の状態の確認、クライアントが送る値。

研究上の再現実験で観察した傾向です。照らさなかった所に欠陥がないという意味ではありません。

合格は、照らした範囲に止める理由が見つからなかった、という結果です。照らさなかった所については、何も言っていません。このため、1回の合格を「欠陥がない証明」として扱わないことが出発点になります。

同じ「合格」でも、分かることは違う

1回のレビューが合格した

その回が照らした範囲の結果

照らさなかった観点には、何も言っていません。合格を、欠陥がないことの証明として扱いません。

同じ版で、結論が回ごとに割れた

ぶれが見えた。合格の回を選ばない

指摘の中身を確かめます。一度でも出た指摘は、他の回の合格で打ち消しません。

確認項目で、毎回拾えた

その項目の観点がそろった

項目にない種類の欠陥まで見つかるとは限りません。新しく出た穴を項目へ足し続けます。

レビュー結果の読み方の比較です。実際のレビューの品質や、コードの安全性を判定する機能ではありません。

合格の回だけを選んでいない?

同じ版で結論が割れたとき、合格の回を採用すれば合格にできてしまいます。一度でも出た指摘は、その中身を確かめてから判断します。

回数を増やす前に、観点を決める

ぶれがあるなら、何回もかければ拾えるのでは、と考えたくなります。ただ、後で紹介する再現実験では、同じ依頼文のまま5回かけても、一度も指摘されなかった欠陥が3件残りました。

先に決めたいのは、**何を確かめてもらうか(観点)**です。観点は、一般的なセキュリティの用語集から作るより、自分の現場で実際に出た穴から作ると、具体的な一文になります。

回数より先に、何を確かめるかを決める

  1. 現場で出た穴を書き出す

    過去の指摘・修正・見逃しを、欠陥の型で並べる。

  2. 確認項目にして依頼文へ

    「1つずつ確かめる」と書き、当てはまれば止める扱いにする。

  3. 同じ版で比べて記録する

    項目ごとに、何回中何回拾ったかを残す。

確認項目は観点をそろえる道具です。項目にない種類の欠陥まで見つかる保証はありません。

例えば、過去に「別の利用者の予定を取り消せた」という穴があったなら、「更新・取り消しは、サーバー側で今の状態と、誰が登録したかまで確かめているか」と書きます。「権限を見て」と頼むより、確かめる対象が具体的です。

確認項目は、項目にない種類の欠陥まで見つける保証にはなりません。新しく出た穴を足していく、育てる前提の道具です。

1回目からあった欠陥を、5回目まで見逃した記録

分類:再現実験。 このサイトの作者自身の個人開発での記録と、その再実行です。公表された事故や脆弱性ではありません。対象のアプリの欠陥はすべて修正済みで、再現の手順はここに載せません。一次資料は研究の記録(research/ai-review-replay)です。

2026年9月28日:14回のレビュー

AI(Claude Code)が書いたログイン機能のPRに、別のAI(Codex)のレビューを、修正しながら約4時間半で14回かけました。このPRには、最初の版から保存型XSSがありました。保存型XSSは、登録された値を画面がエスケープ(記号を文字として表示する処理)せずに表示し、他の人の画面でスクリプトが動いてしまう欠陥です。CWE-79

1〜4回目のレビューは、これを見逃しました。初めて指摘したのは5回目。その5回目は、ドキュメント(docs)だけを変えた版へのレビューで、コードは4回目と同じでした。

作者はこのPRのマージ後に、「docsだけの変更なら、前の合格を使い回してよい」というルールを足していました。このルールが先にあったら、5回目のレビューは行われていなかったことになります。

2026年10月20日:同じ版に5回ずつ、かけ直す

そこで、このPRの最初の版に、同じ依頼文で5回ずつレビューをかけ直しました。レビュー役はCodex(codex-cli 0.157.1)。既知の欠陥6件のうち、1回で何件拾うかを数えています。比べたのは、作者がふだん使っている依頼文そのままと、それに確認項目12行を足したものです。確認項目の全文

表の数字は、5回のレビューのうち、その欠陥を指摘した回数です。

表がはみ出す場合は、横にスクロールして読めます。

既知の欠陥の型 確認項目なし 確認項目あり
AIのツールが、操作している人以外のデータまで読む 5 5
ログイン失敗の回数を、並行アクセスで数え損なう 5 5
取り消しで、持ち主かどうかしか確かめない 1 5
状態を変えるとき、今の状態を確かめない 0 5
引き換えで、クライアントが送った数量・金額を信じる 0 5
保存型XSS 0 2
1回あたりの検出数(平均) 2.2件 5.4件
5回から2回を選ぶ10通りの平均 2.4件 5.7件

確認項目なしでは、保存型XSS・状態の確認漏れ・クライアントの値を信じる穴を、5回とも見ませんでした。2回分の結果を合わせても、平均は2.2件から2.4件にしか増えていません。確認項目ありでは、XSSも2回の組み合わせで数えると10通り中7通りで拾えています。

同じアプリの別の変更(AIのエージェントの処理を足すPR)を対象にした測定では、AIのツールの引数でモデルに「誰のデータか」を選ばせていた穴を、確認項目なしのレビューは5回とも指摘しませんでした(0/5、確認項目ありでは5/5)。

確認項目を足すと、判断が分かれる指摘も1回あたり1件ほど増えました。採点役は誤検知寄り、作者は「起こり得るが優先度は低い」と判断した指摘です。はっきり間違った指摘は、30回の中に見つかっていません。採点の記録

この数字で言えないこと

  • 確認項目は、答えを知ってから書いた。 差の一部は、答えに寄せた効果です。確認項目で拾える上限を確かめた数字として読みます。
  • 知らない欠陥への効果は分からない。 確認項目を作るときに使わなかった欠陥(ホールドアウト)は、どちらでも5/5で差が出ませんでした。
  • 規模が小さい。 各5回、レビュー役は1つのモデル、依頼文は作者自身のもの。傾向までしか言えません。
  • 採点もAI(Claude)。 どちらの依頼文の結果かは伏せましたが、伏せは完全ではなく、人が全件を見直してはいません。
  • 一般の性能ではない。 「AIレビュー一般」や「Codex一般」の検出性能を示す数字ではありません。

学びは、回数より観点が先であること、そして合格を使い回すルールが見逃しを固定し得ることです。

5回のどれも照らさなかった所は、回数では拾えなかった。

回数で増えるのは、すでに照らす可能性がある所です。どの回も照らさない所は、観点として依頼文に書くか、自分のテストで確かめます。

合格を使い回すルールが、穴の通り道になる

守りたいものは、利用者のログイン、別の利用者のデータ、ポイントや金額、個人情報です。そこへ欠陥が届く条件の一つが、合否の判定ルールです。

レビューを毎回かけるのは時間がかかるので、「docsだけの変更なら前の合格を使う」「小さな修正なら再レビューしない」といったルールを足したくなります。ただ、使い回した合格は、前の回が見落とした欠陥も、そのまま次の判断へ運びます。先の記録では、使い回していれば、XSSを最初に指摘した回が行われませんでした。

合格の使い回しは、どの変更まで許す?

  1. 広い使い回しの条件

    「docsだけの変更なら前の合格を使う」。その後のレビューが行われない。

  2. 止める条件を先に決める

    ログイン・権限・お金・個人情報の変更を含む版では、使い回さない。

使い回しは時間を節約しますが、前の合格が見落とした欠陥も、そのまま次の判断へ運びます。

もし見逃したまま公開すれば、例えば保存型XSSは、他の利用者の画面でスクリプトが動く入口になります。状態の確認漏れは、取り消したはずの操作を戻せる穴に、クライアントの値を信じる穴は、送る数値を変えるだけで金額やポイントを変えられる穴になり得ます。どれも、合格の表示からは分かりません。

もう一つの通り道は、依頼文や合否のルールの置き場所です。それらがPRの中のファイルにあると、レビューされる変更と一緒に、ルールも書き換えられます。AIが書いた変更が、意図せず確認項目を減らすこともあり得ます。

依頼文と合否のルールは、変更される側に置かない

  1. PRの中にある設定

    レビューされる変更と一緒に、依頼文や合否の条件も書き換えられる。

  2. 信頼済みの場所にある設定

    取り込み済みの版や別の管理場所から読み、PR側の変更を採用しない。

どこから読むかは、使うレビュー製品とCIの仕様で確かめます。ここでは置き場所の考え方だけを示します。

レビューを起動する場所と、PR側の設定を信頼しない考え方は、AIに任せる権限の教材と更新とAIレビューの運用の教材も参考になります。

モデルに「誰のデータか」を選ばせない

再現実験の別の対象で、確認項目なしのレビューが5回とも指摘しなかったのは、AIのツールの引数で、モデルに対象の人を選ばせていた穴です。モデルが別の人を指定すれば、そのデータも読めます。

直し方は、レビューの依頼文を工夫することではなく、触れる範囲を閉じ込めたツールを渡すことです。対象の人はログインの情報(セッション)で決めて引数から外し、残る引数も、その範囲に含まれるかを処理側で確かめます。

「誰のデータか」を、モデルに選ばせない

  1. 引数で対象の人を受け取るツール

    モデルが別の人を指定すれば、そのデータも読める。

  2. 触れる範囲を閉じ込めたツール

    対象の人はログインの情報で決め、引数から外す。残る引数もその範囲で確かめる。

依頼文で「他の人のデータを読まないで」と頼むことと、ツールで読めなくすることは別です。

OWASPのLLMアプリ向けリスク一覧では、LLMに必要以上の機能・権限・自律性を与えることを「Excessive Agency(過剰な行為主体性)」と呼び、利用者の文脈で動かすことや、許可の判断をLLMに任せず処理側で行うことを対策に挙げています。OWASP LLM06:2025 権限の確認漏れという欠陥の型は、CWE-863に分類されます。

この型はレビューで拾えなかっただけでなく、拾えたとしても、ツールの作りで閉じなければ再発します。エージェントに渡す権限の決め方は、AIに任せる権限の教材で扱っています。

同じ版に3回かけて、結果を表にする

自分の現場で、レビューのぶれを確かめてみます。自分が管理するテスト用のリポジトリか、架空の変更で行います。本番のリポジトリ、利用者のデータ、公開先は使いません。

  1. 自分の現場で過去に出た穴を、確認したい観点として5つほど書き出す(例:持ち主、状態、クライアントの値、エスケープ、回数制限)。
  2. テスト用のリポジトリで、変更を1つ用意する。版(コミット)を固定し、途中で直さない。
  3. 同じ版に、同じ依頼文で3回レビューをかける。毎回、合否と指摘を保存する。
  4. 指摘を読み、1で書いた観点のどれに当たるかを自分で振り分ける。

振り分けた結果を、次のコードで表にします。ローカルのNode.jsで、練習用のファイル(例:review-tally.mjs)に保存してnode review-tally.mjsで実行する想定です。AIやGitHubへの通信はしません。中の記録は架空のダミーです。

// 架空の記録:同じ版に、同じ依頼文で3回レビューした結果
const watch = ["持ち主", "状態", "クライアントの値", "エスケープ", "回数制限"];
const runs = [
  { verdict: "pass", found: ["回数制限"] },
  { verdict: "pass", found: ["回数制限", "持ち主"] },
  { verdict: "fail", found: ["回数制限", "エスケープ"] },
];
function tally(watch, runs) {
  if (!watch.length || runs.length < 2) return ["比べる記録が足りない"];
  const hits = (item) => runs.filter((r) => r.found.includes(item)).length;
  const lines = watch.map((item) => `${item}: ${hits(item)}/${runs.length}`);
  const verdicts = new Set(runs.map((r) => r.verdict));
  lines.push(verdicts.size > 1
    ? "結論: 回によって割れた"
    : `結論: ${runs.length}回とも${runs[0].verdict}`);
  const never = watch.filter((item) => hits(item) === 0);
  lines.push(`一度も見なかった観点: ${never.join("、") || "なし"}`);
  return lines;
}
for (const line of tally(watch, runs)) console.log(line);
持ち主: 1/3
状態: 0/3
クライアントの値: 0/3
エスケープ: 1/3
回数制限: 3/3
結論: 回によって割れた
一度も見なかった観点: 状態、クライアントの値

結果の読み方です。

  • 1/3の観点: 照らす回と照らさない回があります。2回の合格があっても、1回の指摘を打ち消しません。指摘の中身を確かめます。
  • 0/3の観点: 問題がないという意味ではなく、どの回もそこを見ていないという意味です。確認項目として依頼文に書くか、自分のテストで確かめます。
  • 3回ともpass: ぶれが見えなかっただけで、照らしていない観点が残っている可能性はあります。

ログイン・権限・お金・個人情報の観点が0回のまま、または結論が割れたままなら、マージを止めます。自分で判断できない指摘は、その分野を確認できる人に相談します。

このコードは記録を数えるだけで、指摘が正しいか、欠陥があるかは判定しません。振り分けは人が読んで行います。

1か所直したら、同じ型を探す

指摘を直して再レビューが合格しても、同じ書き方が別の場所に残っていることがあります。参考記事では、作者がこのXSSを直すときに同じ型を探したところ、設定ファイルを読み込む処理にも同じ型が見つかったと報告しています。

1か所直したら、同じ型を探す

  1. 指摘された箇所を直す

    直す前に落ち、直した後に通るテストを足す。

  2. 同じ型の箇所を探す

    このPRの外も含め、同じ書き方・同じ入口を調べる。

  3. 調べた範囲と結果を残す

    どこまで探し、何が見つかり、何を調べていないか。

1か所の修正とその合格は、別の場所に残る同じ型を確かめたことになりません。

セキュリティの修正のPRには、「同じ型の箇所:調べた範囲と結果」を1行残します。何も見つからなかった場合も、どこまで調べたかを書いておくと、調べていない範囲と区別できます。再レビューを頼むときも、この1行を依頼文に含めます。

直したのは、その1か所だけ?

同じ入口・同じ書き方の別の場所も見ます。並行アクセスの数え損ない(CWE-362)のように、1か所直すと他も気になる型は少なくありません。

3つの役割で、合格の使い方を確かめる

一人で書いて、頼んで、マージする場合も、役割ごとに確かめる対象を切り替えます。同じ人が兼ねても、それぞれの確認を省略したことにはしません。

変更を書いた人(AIに書かせた人):何を変えたかを先に渡す

AIが変えたファイル、触れたログイン・権限・お金・個人情報の処理を、自分の目で一覧にします。AIの要約だけで変更の範囲を確定しません。危ない処理に触れる変更は、そのことをレビューを頼む人に伝え、修正したら同じ型の箇所を調べた記録を残します。

レビューを頼む人:依頼文と確認項目を持つ

依頼文と確認項目を、PRの外の信頼済みの場所に置き、誰が変えたかをたどれるようにします。危ない変更では、同じ版に複数回かけ、観点ごとの結果を残します。判断できるのは、確認項目に書いた観点で何が見つかったかまで。書いていない観点の安全は判断できません。

合否で公開・マージを決める人:合格の範囲と使い回しを決める

合格がどの版の、どの依頼文と確認項目による結果かを照合します。使い回してよい変更と、使い回さない変更(ログイン・権限・お金・個人情報など)をルールにします。結論が割れた、または重要な観点が一度も見られていない場合は止め、緑のチェックの意味と同じく、表示ではなく中身で判断します。

合格をマージに使う前に

  • 複数回の結果: 危ない変更では、同じ版での複数回のレビュー結果(合否・指摘・版の識別子)が残っている。
  • 現場の確認項目: 確認項目に、自分の現場で実際に出た穴が、欠陥の型の一文として入っている。最後に見直した日が分かる。
  • 使い回しの停止: 危ない変更(ログイン・権限・お金・個人情報)では合格を使い回さない、というルールが文章で決まっている。
  • ルールの置き場所: レビューの依頼文と合否のルールを、PR側(変更される側)から書き換えられないことを、置き場所と読み込み元で確かめた。
  • 同じ型の記録: 修正PRに「同じ型の箇所:調べた範囲と結果」の記録がある。
  • ツールの範囲: AIのツールが触れる範囲を、モデルの引数ではなくログインの情報で閉じ込めている。閉じ込められない箇所は未確認として残している。

次は、検査・公開・権限の教材へ

自動検査の緑のチェックが何を確かめた結果かは、GitHubの検査と公開の境界で整理しています。公開前に、AIへレビューを頼む対象と根拠は公開前の確認へ。AIのツールやエージェントに渡す権限はAIに任せる権限で扱います。

確認項目は、新しい穴が見つかったとき、レビューの依頼文やレビュー役のモデルを変えたとき、危ない変更を含むPRの前に見直します。

一次資料と参考記事

情報確認日:2026年10月25日。数字は2026年10月20日の測定時点のもので、レビュー役の版や依頼文が変われば結果も変わり得ます。

書いた人

マーケティングの現場から、AIをつくり、仕事で使う側へ。実際に試したことや、つまずいたことを、図解と具体例で伝えています。

この記事のURL:https://nekoai-lab.github.io/ai-security-playbook/learn/ai-review-trust/

続けて読む

シリーズ · 全14記事のうち10記事目

次に読むAWSを使う個人開発者へ。所有者・日常の操作・アプリの実行を分け、MFA、短期の認証、信頼する相手、復旧先を具体的に確認する。
読む順番・ルートを見るAIで作って公開する基本
  1. AIに渡す情報を、送る前に分ける
  2. 「学習しない」AIなら、仕事の個人情報を使える?
  3. AIで作ったアプリの、動く場所を知る
  4. AIに「APIキーを設定して」と言われた。どこに入れるのが正解?
  5. APIキーを替えたのに、古いキーが使われている?
  6. ログインと、データを使う権限を分ける
  7. 公開したのは、本当に見せたいファイルだけ?
  8. コードには書いていない。名前やメールは、どこから公開される?
  9. 緑のチェックが付いた。その変更を公開していい?
  10. AIレビューが合格した。その結果を、どこまで信じていい?
  11. AIにデプロイを頼んだ。その認証情報は、どこまでできる?
  12. AIで作ったサービスを、公開する前に確かめる
  13. 外部サービスが止まったら、自分のアプリはどうなる?
  14. 漏えい・異常・消失に気づいたとき、最初にすること

公開前の確認の教材へ戻る →