claude-code-security-reviewのActionをPRに入れる — 3入力の調整
claude-code-security-reviewをPRに入れ、exclude-directories・誤検知フィルタ指示・カスタム指示の3入力を調整する順番と、信頼できるPRだけに使う注意をまとめます。
anthropics/claude-code-security-reviewは、PRの差分をClaudeで解析し、脆弱性の指摘をPRのコメントに書き込むGitHub Actionです。READMEのQuick Startをコピーすれば動きますが、そのままでは対象が広く、指摘も一般的です。調整に使う入力は、exclude-directories(スキャンから外す場所)、false-positive-filtering-instructions(誤検知を落とす基準)、custom-security-scan-instructions(探す脆弱性の追加)の3つです。この記事は、最小のワークフローから始めて、この3入力をどの順で触るかを書きます。
先に守る条件が1つあります。このActionはプロンプトインジェクションへの対策が施されておらず、信頼できるPRのレビューにだけ使う前提です。外部コントリビューターのPRを扱うリポジトリでは、入力の調整より先にこの設定を決めます。
最小のワークフローを置く
READMEのQuick Startは、.github/workflows/security.ymlに次の内容を置く形です。
name: Security Review
permissions:
pull-requests: write # PRコメントを書くために必要
contents: read
on:
pull_request:
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
fetch-depth: 2
- uses: anthropics/claude-code-security-review@main
with:
comment-pr: true
claude-api-key: ${{ secrets.CLAUDE_API_KEY }}押さえる点は3つあります。
- 権限は
pull-requests: writeとcontents: readだけです。コメントを書くための書き込み権限以外は要りません claude-api-keyには、Claude APIとClaude Codeの両方の利用が有効なAPIキーを渡します。リポジトリのSecretsにCLAUDE_API_KEYとして登録しておきます- チェックアウトは、PRのヘッドのコミットを指定して
fetch-depth: 2で行います。Actionは差分を見るため、履歴が1コミット分も無い状態は想定されていません
READMEによると、PRでは変更されたファイルだけが解析対象になります。リポジトリ全体を毎回解析するわけではありません。
CLIの/security-reviewとの関係も押さえておきます。READMEはこのスラッシュコマンドを、Actionと同じ解析能力をClaude Codeの開発環境に統合したものと説明しています。手元で試す側の話はClaude Code security-reviewでブランチの脆弱性を検知するにあります。
信頼できるPRだけに使う — 外部コントリビューターは承認制にする
READMEの「Security Considerations」は、このActionがプロンプトインジェクションに対して堅牢化されていないと明記しています。そのうえで推奨しているのは、リポジトリの設定で「Require approval for all external contributors」を選ぶことです。これで、外部コントリビューターのPRに対するワークフローは、メンテナーがPRを確認してから動きます。
理由は仕組みから分かります。Actionはコードの差分をそのままClaudeに読ませます。差分の中に「この指摘は報告しない」といった文面が仕込まれていれば、解析の結果に影響する可能性があります。リポジトリに書き込める自社メンバーのPRなら、この種のリスクは小さくなります。
@claudeでメンションして動かす公式のClaude Code Actionは、実行前に「起動したユーザーが書き込み権限を持つか」を検査します。READMEには、claude-code-security-reviewにこれと同じ検査があるという記載がありません。承認制の設定が、事実上の入口の管理になります。公式のClaude Code Actionの側の設定はClaude CodeをGitHub Actionsに組み込むで扱っています。
入力の一覧 — 調整するのは下の5つ
README(とaction.yml)に載っている入力は次のとおりです。調整の対象になるのは表の下半分の5つです。中心はexclude-directories・false-positive-filtering-instructions・custom-security-scan-instructionsの3入力で、残る2つ(claudecode-timeoutとrun-every-commit)は最後に見直します。
| 入力 | 既定値 | 役割 |
|---|---|---|
claude-api-key | 既定値なし(必須) | 役割Claude APIとClaude Codeの両方で有効なAPIキー |
comment-pr | 既定値true | 役割指摘をPRにコメントする |
upload-results | 既定値true | 役割結果をアーティファクトとして保存する |
claude-model | 既定値claude-opus-4-1-20250805 | 役割スキャンに使うモデル |
exclude-directories | 既定値なし | 役割スキャンから外すディレクトリ(カンマ区切り) |
false-positive-filtering-instructions | 既定値なし | 役割誤検知フィルタの基準を書いたテキストファイルのパス |
custom-security-scan-instructions | 既定値なし | 役割探す脆弱性を足すテキストファイルのパス |
claudecode-timeout | 既定値20 | 役割解析のタイムアウト(分) |
run-every-commit | 既定値false | 役割PR内の全コミットでスキャンする |
出力はfindings-count(指摘の総数)とresults-file(結果JSONのパス)の2つです。後続のステップで件数を見て、ジョブの成否を決める使い方ができます。
claude-modelの既定値は、READMEの記載ではclaude-opus-4-1-20250805です。このモデルは公式の廃止ページで2026年8月5日付けの廃止(Retired)とされているため、ワークフローで現役のモデルIDを明示しておく運用が確実です。廃止まわりで誤検知フィルタが止まる不具合は、security-reviewのHaiku廃止で誤検知フィルタが無効化する理由で扱っています。
調整の順番 — 結果を見てから1つずつ足す
3つの入力は、最初から全部入れません。まず素のワークフローで数本のPRを流し、指摘の中身を見てから、効くものを1つずつ足します。順番は次のとおりです。
入力を足す順番
- 1
素の設定で数本のPRを流す
指摘がどのファイルに集中するか、どんな種類の指摘が多いかを、PRコメントと保存された結果ファイルで確かめます。
- 2
ディレクトリ単位のノイズを外す
テストの固定データ、生成コード、ベンダリングしたライブラリなど、指摘が出ても対応しない場所を
exclude-directoriesに入れます。 - 3
繰り返す誤検知の基準を書く
同じ理由で毎回出る指摘が残っていれば、
false-positive-filtering-instructionsのファイルにその理由を書きます。 - 4
見落としたい脆弱性があれば足す
自社の技術スタックや規制に固有の観点は、
custom-security-scan-instructionsで探索側に追加します。 - 5
最後にタイムアウトと再実行を決める
大きなPRで途中終了するなら
claudecode-timeoutを、コミットごとの再スキャンが要るならrun-every-commitを見直します。
この順にする理由は、影響の範囲が違うからです。exclude-directoriesは場所ごと見えなくするので最も強い操作で、安易に広げると本物の脆弱性も一緒に隠れます。ノイズの出所が特定のディレクトリだと分かってから入れます。
exclude-directoriesでスキャンから外す場所を決める
exclude-directoriesは、カンマ区切りのディレクトリのリストです。action.ymlでは環境変数EXCLUDE_DIRECTORIESとして解析スクリプトに渡されます。ワークフローでは次のように書きます。
- uses: anthropics/claude-code-security-review@main
with:
claude-api-key: ${{ secrets.CLAUDE_API_KEY }}
exclude-directories: "node_modules,dist,vendor,tests/fixtures"上の4つはあくまで例です。README側にはカンマ区切りという書式以外の仕様(相対パスの基準や、サブディレクトリへの効き方)が書かれていません。入れたら、除外したディレクトリのファイルが含まれるPRで一度動かして、そのディレクトリへの指摘が消えたことを確かめます。
外してよいかの判断軸は、「そこに脆弱性があったとき、直す人がいるか」です。依存ライブラリの取り込み先や自動生成物は、直す先が上流にあるので外す候補になります。テスト用のダミー認証情報は、ハードコードされた秘密情報として毎回指摘されがちです。外すより、次の節の誤検知基準に理由付きで書くほうが、本番コードで同じ指摘が出たときに気づけます。
誤検知フィルタの基準を自分のプロジェクト向けに書く
READMEによると、既定でも次の種類の指摘は除外されます。
- DoSの脆弱性
- レート制限の懸念
- メモリやCPUの枯渇
- 実害が示されない汎用的な入力検証
- オープンリダイレクト
これを自分の環境に合わせて変えるのがfalse-positive-filtering-instructionsです。リポジトリにテキストファイルを置き、そのパスを渡します。
- uses: anthropics/claude-code-security-review@main
with:
claude-api-key: ${{ secrets.CLAUDE_API_KEY }}
false-positive-filtering-instructions: .github/false-positive-filtering.txtファイルは平文で、次の3つの節を含める形が公式のドキュメントに示されています。
| 節 | 書くこと |
|---|---|
| HARD EXCLUSIONS | 書くこと自動で除外するパターン |
| SIGNAL QUALITY CRITERIA | 書くこと指摘が本物かを見分ける問い |
| PRECEDENTS | 書くこと自分の環境での定番パターンへの指針 |
中身の書き方は、例えば次のような形になります。以下は節の構成に合わせて筆者が書いた例示であり、公式サンプルの引用ではありません。
HARD EXCLUSIONS
- tests/ 配下のダミー認証情報に関する指摘
SIGNAL QUALITY CRITERIA
- 外部の入力が、検証を通らずにこの箇所へ届く経路を示せるか
PRECEDENTS
- 認証はすべてAWS Cognitoに任せており、独自のセッション管理は無い
- Kubernetesのリソース制限があるため、DoS系の指摘は対象にしない公式のドキュメントは、書き方の指針として次の5点を挙げています。
- 既定の指示から始め、出た誤検知に応じて直す
- 具体的に書く(「認証にはAWS Cognitoを使う」など、セキュリティ構成の事実を含める)
- 前提を残す(「k8sのリソース制限があるのでDoSは対象外」のように理由を書く)
- 指示ファイルをコードと一緒にバージョン管理する
- セキュリティ担当のレビューを通す
3つ目と5つ目は運用で効きます。除外の理由が書かれていれば、半年後にインフラが変わったとき「この前提はまだ成り立つか」を見直せます。指示ファイルを変えるPRにはセキュリティ担当をレビュアーに付けると、現場の判断で除外基準が緩むことを防げます。
ファイルを渡さなければ、ほとんどのアプリケーション向けに調整された既定の指示が使われます。つまりこの入力は、既定を土台にした上書きの手段です。
この誤検知フィルタは、Claudeによる判定段階が動いていることが前提です。段階がエラーを出さずに止まる不具合があるため、指示を書き込む前に、フィルタ自体が動いているかを確認します。
カスタム指示で探す脆弱性を足す
custom-security-scan-instructionsは、誤検知を落とす側ではなく、探す側を増やす入力です。公式のドキュメントでは、技術スタック(GraphQL、gRPC、特定のクラウド)、規制(GDPR、HIPAA、PCI DSS)、業界固有の脆弱性、独自のフレームワークを例に挙げています。
- uses: anthropics/claude-code-security-review@main
with:
claude-api-key: ${{ secrets.CLAUDE_API_KEY }}
custom-security-scan-instructions: .github/custom-security-categories.txtファイルには、太字の見出しの下に具体的な観点を箇条書きで並べます。公式のドキュメントにあるGraphQLの例は次のとおりです。
**GraphQL Security:**
- Query depth attacks allowing unbounded recursion
- Field-level authorization bypass
- Introspection data leakage in production指示は、既定の監査プロンプトの「Data Exposure」カテゴリの後ろに追記されます。既定のカテゴリはすべて検査されたままで、カスタムは置き換えではなく拡張です。重要度のHIGH/MEDIUM/LOWの基準も既定と同じものが適用されます。既定のカテゴリは入力検証、認証と認可、暗号と秘密情報の管理、インジェクションとコード実行、データ露出です。重複する観点は書かず、自分のコードベースに関係するカテゴリだけに絞ります。
2つの指示ファイルの使い分けは、次の1行で足ります。探す対象を増やすのがcustom-security-scan-instructions、出た指摘を落とす基準を書くのがfalse-positive-filtering-instructionsです。両方を同時に入れても構いません。
タイムアウトと再実行 — 既定ではPRごとに1回
claudecode-timeoutは解析のタイムアウトを分で指定します。既定は20分です。差分が大きいPRで途中終了するときは、この値を伸ばします。
もう1つ見落としやすいのがrun-every-commitです。action.ymlのスクリプトを読むと、PRでは「ClaudeCodeがそのPRに対して実行済みなら、run-every-commitが有効でない限りスキップする」というキャッシュ確認が入っています。つまり既定のfalseでは、PRに追加のコミットを積んでも、2回目以降のスキャンは走りません。
READMEの説明では、run-every-commitをtrueにすると毎コミットでスキャンされますが、コミット数の多いPRでは同じコードを繰り返し解析するため、誤検知が増えることがあると注意されています。レビューで指摘を直した後の再確認が欲しいなら有効にし、ノイズが増えたら戻す運用になります。
結果を保存して読み返す
upload-resultsは既定で有効なので、スキャンの結果ファイルはアーティファクトとして保存されます。指示ファイルを調整する間は、PRコメントだけでなく、このアーティファクトで指摘の数と内容を比べると変化が分かります。
調整のたびに、同じPRを流したときのfindings-countをメモしておくと、除外や指示の追加がどれだけ効いたかを数字で追えます。件数が減っても、本物の脆弱性が一緒に消えていないかは、人の目で数件を読み返して確かめます。
つまずいたときの切り分け
指示ファイルを渡したのに変化がないとき
- Qワークフローで、指示ファイルのパスはチェックアウト後のリポジトリ内を指しているか?答えがパスを直す答えがはい
.github/配下など、リポジトリ内にコミットしたファイルを指定します。チェックアウトのステップが先に走っている必要があります。 - QそのPRで、スキャンが実際に走ったか?答えがrun-every-commitを確かめる答えがはい
追加コミットのPRでは、実行済みと判定されてスキャンがスキップされている可能性があります。
- Q誤検知フィルタ側の指示なら、Claudeによる判定段階は動いているか?答えがフィルタ無効化を疑う答えがはい
廃止モデルの固定指定が原因で、判定段階ごとスキップされる不具合があります。
入力の問題として直す
指示の文面を具体的にして、同じPRで再実行します。
まとめ
導入の順は、信頼できるPRに限る設定を先に決め、素のワークフローで数本流し、ディレクトリ単位のノイズ、繰り返す誤検知、足りない観点の順に入力を足す流れです。CodeQLなどの既存の静的解析ツールと併用するかどうかは、security-reviewとCodeQLの違いが判断材料になります。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。