semgrep について
semgrepは、Semgrepでコードベースの静的セキュリティスキャンを行うスキルです。セキュリティ監査やレビュー前の確認向けに、言語別ルールセットの実行、SARIF結果の統合、失敗・スキップしたスキャンの記録を行います。
主な機能
- 01プログラミング言語の自動検出
- 02ルールセットスキャンの並列実行
- 03全件・重要項目のみのモード
- 04SARIFスキャン結果の統合
- 05失敗・スキップしたスキャンの記録
活用シーン
- 01コードベースのセキュリティ監査
- 02コードレビュー前の脆弱性検出
- 03既知の不具合パターンのスキャン
- 04複数ルールセットの結果統合
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ trailofbits/ skills --skill semgrepインストール後、Claude Code で/semgrepを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlassets/trail-of-bits-mark.svgreferences/rulesets.mdscan-modes.mdscripts/merge_sarif.pyrun-scans.shtest_merge_sarif.pyworkflows/scan-workflow.md詳細
Semgrep セキュリティスキャン
言語の自動検出、並列実行、SARIF 出力の統合により、Semgrep スキャンを実行します。
基本原則
- 必ず
--metrics=offを使用してください — Semgrep はデフォルトでテレメトリーを送信します。--config autoも外部に接続します。セキュリティ監査中のデータ漏えいを防ぐため、すべてのsemgrepコマンドに--metrics=offを含めてください。 - スキャン計画にはユーザーの承認が必要です(ステップ 3 は必須の承認ゲートです) — 元の「このコードベースをスキャンして」という依頼は承認ではありません。ルールセット、対象、エンジン、モードを正確に提示し、スキャナーを起動する前に明示的な「はい」または「進めてください」を待ってください。
- サードパーティーのルールセットは必須です。任意ではありません — Trail of Bits、0xdea、Decurity のルールは、公式レジストリにはない脆弱性を検出します。検出された言語に該当する場合は必ず含めてください。
- コマンドは
scripts/run-scans.shで生成してください。自分で記述しないでください — このスクリプトは、承認済みリストからすべてのsemgrepコマンドを組み立てます。これにより、--metrics=off、--includeのスコープルール、並列ディスパッチの特性が、指示ではなくコードによって保証されます。承認済みのルールセットを渡して実行してください。 - スキャンの前に必ず Semgrep Pro の有無を確認してください — Pro はファイルをまたぐ汚染追跡を有効にし、真陽性を約 250%多く検出します。確認を省くと、ファイル間の重大な脆弱性を気づかないまま見逃すことになります。
- 実行されなかった項目も報告してください —
scans.jsonにはscansとともにfailedとskippedが記録されます。リポジトリをクローンできなかったルールセットや、スキャンがゼロ以外の終了コードを返した場合は、必ずレポートに記載してください。不完全なスキャンを完全なものとして提示するのは、スキャンを実施しないよりも問題です。
使用する場合
- コードベースのセキュリティ監査
- コードレビュー前の脆弱性検出
- 既知のバグパターンのスキャン
- 初回の静的解析
使用しない場合
- バイナリ解析 → バイナリ解析ツールを使用してください
- すでに Semgrep CI を設定済み → 既存のパイプラインを使用してください
- ファイル間解析が必要だが Pro ライセンスがない → 代替として CodeQL を検討してください
- Semgrep のカスタムルールを作成する →
semgrep-rule-creatorスキルを使用してください - 既存のルールを他の言語に移植する →
semgrep-rule-variant-creatorスキルを使用してください
出力ディレクトリ
すべてのスキャン結果、SARIF ファイル、一時データは、単一の出力ディレクトリに保存されます。
- ユーザーがプロンプトで出力ディレクトリを指定した場合は、それを
OUTPUT_DIRとして使用してください。 - 指定されていない場合は、デフォルトで
./static_analysis_semgrep_1を使用してください。すでに存在する場合は、_2、_3のように番号を増やしてください。
どちらの場合も、ファイルを書き込む前に必ず mkdir -p でディレクトリを作成してください。
# Resolve output directory
if [ -n "$USER_SPECIFIED_DIR" ]; then
OUTPUT_DIR="$USER_SPECIFIED_DIR"
else
BASE="static_analysis_semgrep"
N=1
while [ -e "${BASE}_${N}" ]; do
N=$((N + 1))
done
OUTPUT_DIR="${BASE}_${N}"
fi
mkdir -p "$OUTPUT_DIR/raw" "$OUTPUT_DIR/results"
出力ディレクトリはステップ 1 の開始時に一度だけ決定し、その後のすべてのステップで使用します。
$OUTPUT_DIR/
├── rulesets.json # The approved plan (Step 3), read by run-scans.sh (Step 4)
├── scans.json # What ran, failed, skipped, and covered nothing (Step 4)
├── raw/ # Per-scan raw output (unfiltered)
│ ├── python-python.json # <language>-<ruleset> for language-scoped rules
│ ├── python-python.sarif
│ ├── python-django.json
│ ├── python-django.sarif
│ ├── all-security-audit.json # all-<ruleset> for cross-language rules, run once
│ ├── all-security-audit.sarif
│ └── ...
└── results/ # Final merged output
└── results.sarif
前提条件
必須: Semgrep CLI(semgrep --version)。インストールされていない場合は、Semgrep のインストールドキュメントを参照してください。
任意: Semgrep Pro — ファイルをまたぐ汚染追跡、手続き間解析、および追加の言語(Apex、C#、Elixir)を有効にします。次のコマンドで確認してください。
# --metrics=off because Principle 1 has no exceptions, and this is the first semgrep command
# of a run. stderr is kept because "OSS only" has several causes (logged out, no subscription,
# registry blocked) and the run downgrades silently for all of them.
if PRO_ERR=$(semgrep --pro --validate --metrics=off --config p/default 2>&1); then
echo "Pro available"
else
echo "OSS only"
echo " reason: $(printf '%s' "$PRO_ERR" | tail -n 3)"
fi
制限事項: OSS モードでは、ファイルをまたぐデータフローを追跡できません。Pro モードはファイル間解析に -j 1 を使用します(ルールセットごとの処理は遅くなりますが、ルールセットの並列実行で補います)。
スキャンモード
ステップ 2 でモードを選択してください。モードによって、スキャンのフラグと後処理の両方が変わります。
| モード | 対象範囲 | 報告される検出結果 |
|---|---|---|
| すべて実行 | すべてのルールセット、すべての重大度レベル | すべて |
| 重要項目のみ | すべてのルールセット、事前および事後にフィルタリング | セキュリティ上の脆弱性のみ、中〜高の確信度/影響度 |
重要項目のみでは、次の 2 段階のフィルタリングを適用します。
- 事前フィルター:
--severity WARNING --severity ERROR(CLI フラグ) - 事後フィルター: JSON メタデータ —
category=security、confidence∈{MEDIUM,HIGH}、impact∈{MEDIUM,HIGH}のみを保持
メタデータの条件と jq フィルターコマンドについては、scan-modes.md を参照してください。
オーケストレーションアーキテクチャ
┌──────────────────────────────────────────────────────────────────┐
│ MAIN SESSION (this skill) │
│ Step 1: Detect languages + check Pro availability │
│ Step 2: Select scan mode + rulesets (ref: rulesets.md) │
│ Step 3: Present plan + rulesets, get approval [⛔ HARD GATE] │
│ Step 4: Run scripts/run-scans.sh with the approved rulesets │
│ Step 5: Post-filter, merge, report, delete repos/ │
└──────────────────────────────────────────────────────────────────┘
│ Step 4: Bash
▼
┌──────────────────────────────────────────────────────────────────┐
│ scripts/run-scans.sh │
│ clone each third-party repo once, into repos/ │
│ generate one semgrep command per ruleset │
│ ├── python p/python, p/django --include=*.py│
│ ├── javascript p/javascript --include=*.js│
│ ├── docker p/dockerfile │
│ └── cross-language p/security-audit, p/secrets, │
│ the cloned repos (no filter) │
│ run in batches of --jobs, exit code read per process │
│ write scans.json — scans, failed, skipped │
└──────────────────────────────────────────────────────────────────┘
承認ゲートはセッション内に残ります。スクリプトは実行のみを担い、質問はしません。 承認済みのリストは JSON ファイルとして渡されるため、スキャンがユーザーの拒否した ルールセットに及ぶことはありません。
複数の言語に適用するルールセットは、言語ごとに繰り返すのではなく、共通の単位にまとめます。
p/security-audit、p/secrets、サードパーティのリポジトリは対象全体をスコープ指定なしで
スキャンするため、言語ごとに実行すると同じコマンドが N 回実行され、SARIF の
マージ時に重複を除去することになっていました。
ワークフローとしての実行
このプラグインには /static-analysis:semgrep-scan が用意されており、言語と Pro の検出、
rulesets.md からのルールセットの選択、scripts/run-scans.sh の実行、
マージとレポート作成まで、スキャン全体をエンドツーエンドで実行します。文章ではなく、
JSON オブジェクトを渡してください。
/static-analysis:semgrep-scan {"target": "/abs/path", "mode": "run-all"}
ルールセットの承認で停止することはありません。 対象を指定して呼び出すことがオプトインとなり、
/variant-analysis:variants と同じです。対象へのスキャンは読み取り専用であるため、安全に実行できます。
--autofix は使わず、書き込みはすべて出力ディレクトリ内で行われます。そのため、以下の承認ゲートは
安全性の確認ではなく、スコープの確認です。いずれの場合も、実行された内容は
rulesets.json と scans.json に記録されます。
スキャンを実行したい場合はワークフローを使ってください。ルールセットの選択自体が重要で、 先にリストを確認して編集したい場合は、以下の 5 つの手順を実行してください。
ワークフロー
scan-workflow.md の詳細なワークフローに従ってください。 概要:
| 手順 | アクション | ゲート | 主要な参照先 |
|---|---|---|---|
| 1 | 出力ディレクトリを解決し、言語と Pro の利用可否を検出する | — | Bash ではなく Glob を使用 |
| 2 | スキャンモードとルールセットを選択する | — | rulesets.md |
| 3 | 実行計画を提示し、明示的な承認を得る | ⛔ HARD | AskUserQuestion |
| 4 | スキャンを実行する | — | scripts/run-scans.sh |
| 5 | 後処理フィルターを適用し、マージ、レポート作成、クリーンアップを行う | — | マージスクリプト(以下) |
タスクの強制: 呼び出し時に、依存関係を blockedBy で設定した 5 つのタスクを作成します(各手順が直前の手順をブロックします)。手順 3 は HARD GATE です。ユーザーが明示的に承認した後に限り、完了としてマークしてください。
マージコマンド(手順 5):
# run-all
uv run --no-project {baseDir}/scripts/merge_sarif.py "$OUTPUT_DIR/raw" "$OUTPUT_DIR/results/results.sarif" \
--scans "$OUTPUT_DIR/scans.json"
# important-only, once the JSON post-filter has run over every file in raw/
uv run --no-project {baseDir}/scripts/merge_sarif.py "$OUTPUT_DIR/raw" "$OUTPUT_DIR/results/results.sarif" \
--important --scans "$OUTPUT_DIR/scans.json"
--scans を指定すると、.failed に記載されたスキャンの出力が除外されます。途中で失敗したスキャンでも
.sarif を書き出している場合があり、--important を指定すると、そのファイルには後処理フィルターが
適用されていないため、空のフィルターではなくエラーになります。このフラグがないと、失敗したスキャンが
すべての正常なスキャンのマージ結果を妨げます。除外されたファイルは標準出力に表示されるため、
レポートに記載できます。
後処理フィルターは、SARIF に含まれないメタデータを読み取るため、マージ済みファイルに対して
再実行できません。代わりに --important を指定すると、JSON フィルターで残された検出結果を
(rule, file, line) に基づいて保持します。指定しない場合、results.sarif はフィルターなしですが、
JSON 側にはフィルターが適用されています。
ワークフローとエージェント
| コンポーネント | 目的 |
|---|---|
scripts/run-scans.sh | 承認済みのルールセットから各スキャンコマンドを構築し、バッチごとに実行して scans.json を書き出します |
手順 4 は Bash の呼び出しです。サブエージェントがスキャンの一部を実行することはありません。 終了コードと検出件数は、プロセスとプロセスが書き出した JSON から読み取ります。
却下すべき合理化
| 近道 | それが間違っている理由 |
|---|---|
| 「ユーザーがスキャンを依頼したのだから、それは承認です」 | 元の依頼 ≠ 計画の承認です。計画を提示し、AskUserQuestion を使用して、明示的な「はい」を待ってください |
| 「ステップ 3 のタスクがブロックされているので、完了にしてしまいましょう」 | タスクのステータスについて嘘をつくと、強制の仕組みが機能しなくなります。実際に承認された後でのみ完了にしてください |
| 「ユーザーの希望はもう分かっています」 | 思い込みによって、誤ったディレクトリやルールセットをスキャンしてしまうことがあります。確認のため計画を提示してください |
| 「デフォルトのルールセットを使えばよいでしょう」 | スキャンの前に、ユーザーが使用するルールセットを確認して承認する必要があります |
| 「確認せずにルールセットを追加しましょう」 | 同意なく承認済みのリストを変更すると、信頼を損ないます |
| 「サードパーティのルールセットは任意です」 | Trail of Bits、0xdea、Decurity は公式レジストリにない脆弱性を検出するため、必須です |
| 「--config auto を使いましょう」 | メトリクスが送信され、ルールセットの制御性も低下します |
| 「Semgrep のコマンドは自分で実行すればよいでしょう」 | run-scans.sh は --metrics=off、--include ルール、出力ディレクトリの --exclude を確実に適用します。手書きのコマンドでは、これらが気付かれないまま抜け落ちます |
| 「スクリプトが失敗したので、結果を得るために Semgrep を直接実行しましょう」 | 終了コードが 0 以外の場合、スキャンは成功していません。そのことを報告して中止してください。手動で実行した一部のスキャンを、完全なスキャンのように見せてしまいます |
| 「一部のスキャンは失敗しましたが、実行自体は完了しました」 | failed と skipped は scans.json に記録されています。それらを報告しないと、ユーザーは部分的なスキャンを問題のない結果だと受け取ってしまいます |
| 「Pro は遅すぎるので、--pro は省きましょう」 | ファイル間分析により、真陽性を 250% 多く検出できます。時間をかける価値があります |
| 「Semgrep は GitHub URL を標準で扱えます」 | 標準形式でない YAML を含むリポジトリでは URL の処理に失敗します。必ず先にクローンしてください |
| 「クリーンアップは任意です」 | クローンしたリポジトリがユーザーのワークスペースを汚し、実行のたびに蓄積されます |
「ターゲットには . や相対パスを使いましょう」 | サブエージェントが曖昧さを避けられるよう、絶対パスを指定する必要があります |
| 「出力ディレクトリは後でユーザーに選んでもらいましょう」 | 出力ディレクトリは、ファイルを作成する前のステップ 1 で確定する必要があります |
参照インデックス
| ファイル | 内容 |
|---|---|
| rulesets.md | ルールセットの完全なカタログと選択アルゴリズム |
| scan-modes.md | フィルター前後の基準と jq コマンド |
| ワークフロー | 目的 |
|---|---|
| scan-workflow.md | スキャン実行の完全な 5 ステップのプロセス |
scripts/run-scans.sh | ステップ 4 で呼び出すスキャンランナー |
成功基準
- 出力ディレクトリが確定している(ユーザー指定、または自動採番されたデフォルト)
- 生成されたすべてのファイルが
$OUTPUT_DIR内に保存されている - ファイル数とともに言語が検出され、Pro のステータスが確認されている
- スキャンモードがユーザーによって選択されている(すべて実行/重要なもののみ)
- 検出されたすべての言語について、ルールセットにサードパーティのルールが含まれている
- ユーザーがスキャン計画を明示的に承認している(ステップ 3 のゲートを通過)
-
run-scans.shが終了コード 0 で終了し、$OUTPUT_DIR/scans.jsonを書き出している -
scans.jsonのfailedとskippedが空であるか、レポートに記載されている -
scans.jsonでpartialとされたスキャンがないか、レポートに記載されている — それらのスキャンでは、一部のルールのコンパイルに失敗しています - すべての
semgrepコマンドで--metrics=offが使用されている - ステップ 3 のゲートで、承認済みの計画が
$OUTPUT_DIR/rulesets.jsonに書き込まれ、変更されずにスキャナーへ渡されている -
scans.jsonのcoveredNothingが空であるか、レポートに記載されている -
scans.jsonのoversizedが空であるか、レポートに記載されている — これらのファイルは--max-target-bytesの上限を超えており、どのルールセットも読み込んでいません - スキャンごとの生出力が
$OUTPUT_DIR/raw/に保存されている -
$OUTPUT_DIR/results/にresults.sarifが存在し、有効な JSON である - 重要なもののみのモード:マージ前に後処理フィルターが適用され、
--importantを指定してマージが実行され、フィルター前の結果がraw/に保持されている - 結果の概要が、重大度とカテゴリ別の内訳とともに報告されている
- クローンしたリポジトリ(存在する場合)が
$OUTPUT_DIR/repos/からクリーンアップされている