Semgrep(セムグレップ)は、ソースコードを構文木として読み、書いたパターンに一致する箇所を探す静的解析ツールです。開発元は米Semgrep社で、エンジンのCommunity Edition(CE)はLGPL-2.1のオープンソースとして公開されています。名前は「semantic grep」に由来し、文字列ではなくコードの構造で一致を判定します。
この記事では、2026年10月7日公開の v1.180.0 をmacOSに入れ、インストール、自作ルール、taint解析、autofix、CI組み込みを実際に動かした結果をもとに、使い方と料金、無料版で検出できない範囲を整理します。SAST全般の位置づけはSASTとDAST・SCAの違いを解説した記事を参照してください。
まとめ:Semgrepの要点と導入判断
- Semgrepはコードをパースしてパターンを照合するSASTツール。ルールは対象言語とほぼ同じ書き方のYAMLで、変数名や空白、import時の別名の違いを吸収して一致させる
- CLIは
pipx install semgrepかbrew install semgrepで入る。Windowsも2025年秋のリリースでネイティブ対応がGAになった - 無料のCE版のtaint解析は1つの関数の中だけを追う。関数やファイルをまたぐ流れは、自作のtaintルールでは検出されなかった(実測)
- 料金はFree Edition(コントリビューター10人・非公開リポジトリ10本まで0円)、Teams(Code・Supply Chainが各月30ドル、Secretsが月15ドル/1コントリビューター)、Enterprise(個別見積)
- 公式ルール(semgrep-rules)は2024年12月から「Semgrep Rules License v1.0」で、自社内での利用に限られる。これを受けてフォークのOpengrepが生まれた
- 独自ルールを素早く書いて回したいならSemgrep、GitHub上で深いデータフロー解析をしたいならCodeQL、コード品質の総合管理ならSonarQubeが向く
Semgrepの仕組みとgrepとの違い
構文木への照合で起きる差:grepとの検出件数の比較
grepは文字の並びで一致を探すため、書き方の揺れや「危険でない呼び出し」を区別できません。Semgrepはコードを抽象構文木に変換したうえで照合するので、空白の違いや引数の順序、from subprocess import run as r のような別名importも同じ呼び出しとして扱えます。
次のPythonファイルに対して、shell=True 付きの subprocess.run を探してみました。grepは grep -rn "subprocess.run.*shell *= *True"、Semgrepは後述の自作ルールです。対象は外部入力の連結、引数の変数渡し、定数文字列、抑制コメント付きの4か所と、別ファイルの別名呼び出しです。
| 呼び出し | grep | Semgrep(自作ルール) |
|---|---|---|
"ping -c 1 " + host を渡す |
一致 | 検出 |
引数 cmd を渡す(shell = True と空白あり) |
一致 | 検出 |
定数 "ls -l" を渡す |
一致 | 除外 |
引数 cmd2 に nosemgrep コメント付き |
一致 | 除外 |
別名 r(x, shell=True)(別ファイル) |
不一致 | 検出 |
grepは4行すべてを拾い、別名で呼んだ1行は拾えませんでした。Semgrepは定数文字列を pattern-not で、抑制コメント付きの行を nosemgrep で除外し(コメントを外すと同じ行が検出されます)、別名の呼び出しは検出しています。レビューで目視する件数が減るのは、この「除外の条件をコードの構造で書ける」点によります。静的解析一般の仕組みは静的解析の仕組みとツールの選び方で解説しています。
製品構成:Code・Supply Chain・SecretsとCE版の関係
Semgrepの名前は、CLIのエンジンと、Semgrep社のクラウド(AppSec Platform)の両方を指します。プラットフォームの製品は3つに分かれています。
- Semgrep Code:自社コードのSAST。公式の対応言語表では「35+ languages」
- Semgrep Supply Chain:依存パッケージの脆弱性検出(SCA)。対応は14言語で、脆弱な関数が実際に呼ばれているかを見る到達可能性(reachability)解析を持つ
- Semgrep Secrets:ハードコードされた認証情報の検出
CE版はこのうちCodeのエンジン部分だけを無料・ローカルで動かすもので、SAST・SCA・シークレットを合わせて「20000+」あるとv1.180.0のREADMEが記すSemgrep社独自のルール(Code向けのPro rulesは同READMEで「600+」)は含みません。ファイルをまたぐデータフロー解析(cross-file)は、対応言語表でPro向けの機能として書き分けられています。C#・Go・Java・JavaScript・Kotlin・Python・TypeScript・C/C++がcross-file対応、Ruby・PHP・Rust・Swiftなどは関数間(cross-function)までです。
Semgrepのインストールと初回スキャンの手順
公式のCE向けクイックスタートが最初に挙げる導入方法はpipxで、uvも並記されています。Homebrewは「best-effort」の扱いで、最新版への追随が遅れることがあると注記されています(2026年10月9日時点のHomebrewの安定版は1.180.0で、遅れはありません)。Dockerイメージでも動きます。PyPI上の最新版は2026年10月7日の 1.180.0 で、必要なPythonは3.10以上です。Windowsは、Semgrep社の2025年秋のリリースノートで「WSLやDockerなしでpipから入れて使える」ネイティブ対応がGAになりました(CE向けクイックスタートのタブ表記は「Windows (beta)」のまま残っています)。
# どれか1つ
pipx install semgrep
uv tool install semgrep
brew install semgrep
docker run --rm -v "${PWD}:/src" semgrep/semgrep semgrep scan --config p/python
semgrep --version # 1.180.0
初回は公開レジストリのルールセットを名前で指定して走らせるのが確実です。手元の5ファイルに p/python を当てると、151ルールが実行され9件が検出されました(ルールセットのダウンロード込みで実時間9.74秒)。
semgrep scan --config p/python --metrics=off .
# Scanning 5 files with 151 python rules.
# • Findings: 9 (9 blocking)
つまずきやすい挙動が2つあります。
--config autoは匿名メトリクスの送信が前提:--metrics=offと併用するとCannot create auto config when metrics are off.で止まります。社外にリポジトリ情報を送りたくない場合は、p/pythonのようにルールセットを明示します- 検出があっても終了コードは0:
semgrep scanは既定で0を返すため、CIを止めたいときは--errorを付けます(付けると終了コード1)
semgrep ci はSemgrep社のプラットフォームと連携するコマンドで、ログインせずに実行すると run `semgrep login` before using `semgrep ci` or use `semgrep scan` and set `--config` と表示されます。CE版だけで運用するなら semgrep scan を使います。
カスタムルールの書き方:YAMLとパターン構文
pattern・メタ変数・pattern-notの基本形
ルールはYAMLで、id・languages・severity・message と、一致条件を書きます。$CMD のように $ で始まる大文字はメタ変数で、任意の式に一致し、メッセージや修正案で参照できます。"..." は任意の文字列リテラルを表します。
rules:
- id: subprocess-shell-true
languages: [python]
severity: WARNING
message: subprocess を shell=True で呼んでいます。引数リストで渡してください
patterns:
- pattern: subprocess.run($CMD, shell=True)
- pattern-not: subprocess.run("...", shell=True)
fix: subprocess.run(shlex.split($CMD))
patterns の下に並べた条件はANDで結ばれ、pattern-not で除外します。ORにしたいときは pattern-either を使います。前の比較表で定数文字列が除外されたのは、2行目の pattern-not によるものです。
taintモードによる入力値の追跡:SQLインジェクションの例
「外部入力が危険な関数に届くか」を見るには mode: taint を使い、入力元(source)と到達先(sink)を指定します。
rules:
- id: flask-sqli
languages: [python]
severity: ERROR
message: リクエスト値が SQL 文字列に連結されて execute に渡っています
mode: taint
pattern-sources:
- pattern: flask.request.args.get(...)
pattern-sinks:
- patterns:
- pattern-inside: $CONN.execute($Q, ...)
- focus-metavariable: $Q
Flaskの同じファイルに「文字列連結でSQLを組む関数」と「プレースホルダ ? で値を渡す関数」を並べると、検出されたのは連結した側の conn.execute(q) の行だけでした。プレースホルダ側は、値がSQL文字列ではなく別の引数として渡るため、sinkの $Q に入力が届かず検出されません。入力値の検証側の設計は入力バリデーションの許可リスト設計で扱っています。
autofixの落とし穴:importは足されず別名は書き換わる
fix: を書いたルールは --autofix で修正を適用できます。ただし置換は一致した式を文字列として書き換えるだけで、必要なimportも、書き換え後の構文の正しさも確かめません。今回のルールでは次の2つが起きました。
shlex.splitに置き換えてもimport shlexは追加されない。そのまま実行するとNameErrorになるfrom subprocess import run as rの別名呼び出しr(x, shell=True)は、修正案がsubprocess.run(shlex.split(x))になる。このファイルではsubprocess自体をimportしていないので、やはり動かない
別名を吸収して検出できる仕組みが、修正では逆に働きます。autofixはPRへの提案コメントにとどめ、自動コミットはlinterとテストが通ることを条件にするのが安全です。
ルールのテスト:ruleid・okコメントで期待値を固定
自作ルールは、対象言語のテストファイルに期待値をコメントで書いて検証できます。ルールと同じ名前のファイル(shell.yaml と shell.py)を同じディレクトリに置き、semgrep scan --test を実行します。
import subprocess
def a(cmd):
# ruleid: subprocess-shell-true
subprocess.run(cmd, shell=True)
def b():
# ok: subprocess-shell-true
subprocess.run("ls", shell=True)
$ semgrep scan --test t/
1/1: ✓ All tests passed
# ruleid: の次の行は「検出されるべき」、# ok: の次の行は「検出されてはいけない」を意味します。ルールを直したときに誤検知や見逃しが戻っていないかを、CIで毎回確かめられます。
無料のCommunity Editionで検出できない範囲の実測
CE版を評価するときに最も確かめておきたいのが、taint解析の到達範囲です。同じSQLインジェクションを「同じ関数内」「同じファイルの別関数」「別ファイルの関数」の3通りに書き分け、上の自作taintルールと公開ルールセット p/python の両方を当てました。
| 入力からexecuteまでの経路 | 自作taintルール | p/python |
|---|---|---|
| 同じ関数内で連結してexecute | 検出 | 検出 |
| 同じファイルの別関数でexecute | 未検出 | 検出 |
| 別ファイルの関数でexecute | 未検出 | 検出 |
自作ルールが関数をまたいだ時点で見逃したのは、CEのtaint解析が1つの関数の中だけを追うためです。関数をまたぐ解析(--pro-intrafile)とファイルをまたぐ解析は、Semgrep社のプラットフォームに接続して使うPro Engineの機能です。
一方で p/python の tainted-sql-string は、3通りとも検出しました。このルールはsinkを execute ではなく「リクエスト値をSQLらしい文字列に連結した箇所」に置いているため、連結が入力と同じ関数にある限り、executeがどこにあっても拾えます。CE版で見逃しを減らすには、sinkを危険な関数の呼び出しではなく、入力が危険な形に加工される地点に置くのが有効です。
逆に、入力の受け取りと文字列の組み立てを別の関数やファイルに分ける構成(リポジトリ層やクエリビルダーを自作している場合など)では、CE版の見逃しは避けられません。そうしたコードベースで脆弱性検出を主目的にするなら、Free EditionやTeamsでPro Engineを使うか、データフロー解析を前提とするCodeQLを検討します。静的解析が構造的に見逃すものは静的コード解析の誤検知と限界にまとめています。
CI/CDへの組み込み:GitHub Actionsと差分スキャン
CE版をGitHub Actionsで動かすワークフロー
公式のCI設定例は、Semgrep入りのコンテナイメージ semgrep/semgrep の中で実行する形です。CE版の例では semgrep scan --config auto になっていますが、前述のとおり auto はメトリクス送信が前提なので、ここではルールセットを明示し、検出時にジョブを失敗させる --error を付けています。自作ルールはリポジトリ直下の .semgrep/ に置く前提です。
name: Semgrep CE scan
on:
pull_request: {}
push:
branches: ["main"]
permissions:
contents: read
jobs:
semgrep:
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
if: (github.actor != 'dependabot[bot]')
steps:
- uses: actions/checkout@v6
- run: semgrep scan --config p/python --config .semgrep/ --metrics=off --error
Semgrep社のプラットフォームを使う場合は、最後の行を semgrep ci にし、環境変数 SEMGREP_APP_TOKEN にトークンを渡します。こちらはPRで変更されたファイルだけを見る差分スキャンが既定です。permissions の考え方はGitHub Actionsのpermissionsの既定権限と最小権限を参照してください。
既存の検出を除外する差分スキャン(--baseline-commit)
既存コードに大量の検出があるリポジトリで全件をブロック対象にすると、導入初日にCIが止まります。CE版では --baseline-commit で基準コミットを指定すると、それ以降に増えた検出だけが報告されます。
semgrep scan --config .semgrep/ --baseline-commit HEAD~1 --metrics=off .
# 全件スキャン:22・26・35行目の3件
# 基準コミット指定:今回追加した35行目の1件だけ
PRのベースブランチを基準にすれば「新しく持ち込んだ問題だけを止め、既存分は別途計画的に減らす」運用になります。actions/checkout は既定で直近1コミットしか取得しないため、CIで基準ブランチを指定するときは fetch-depth: 0 で履歴を取得しておきます。誤検知と判断した箇所は、行末の # nosemgrep: ルールID で個別に、生成コードやテスト用の脆弱なサンプルはリポジトリ直下の .semgrepignore でファイル単位に除外します。
料金プランとライセンス:無料で使える範囲
2026年10月時点の公式料金ページの内容です。金額は1コントリビューターあたりの月額(ドル建て)で、改定や契約条件で変わるため、契約前に公式ページで確認してください。
| プラン | 料金 | 上限 | 主な内容 |
|---|---|---|---|
| Community Edition | 0円 | なし | ローカルCLI・関数内のtaint解析 |
| Free Edition | 0円 | 10人・非公開リポジトリ10本 | Code・Supply Chain・Pro rules・AIクレジット60 |
| Teams | Code 30ドル・Supply Chain 30ドル・Secrets 15ドル | 非公開リポジトリ500本 | SSO・AIクレジット月20/人 |
| Enterprise | 個別見積 | なし | オンプレSCM対応・専用基盤・AIクレジット月50/人 |
公開リポジトリはどのプランでも本数無制限です。料金と上限の「コントリビューター」は、直近90日にSemgrepでスキャンした非公開リポジトリへ1回以上コミットした人を指します。
Free Editionはcross-file解析とPro rulesを含むため、コントリビューター10人以下で非公開リポジトリが10本以内なら、CE版より先にこちらで検出結果を比べるのが近道です。公式料金ページのFAQによれば、ローカルやCIで実行する限りソースコード自体は外に出ず、Semgrep社へ送られるのは実行のメタデータ(検出結果を含む)です。AI機能を有効にすると検出箇所を含むファイルの一部が、Managed Scansを使うとリポジトリのクローンがSemgrep側へ渡ります。メタデータの送信も許されない案件ではCE版(--metrics=off)を選びます。
ライセンス面では、エンジン本体(semgrep/semgrep)がLGPL-2.1である一方、Semgrep社は2024年12月13日に「Semgrep OSS」を「Semgrep Community Edition」へ改称し、同日付で公式ルール集 semgrep-rules を「Semgrep Rules License v1.0」に切り替えました。それまでのルール集はLGPL-2.1に「Commons Clause」(ルールの機能を主な価値とする製品・サービスの販売を禁じる条件)を付けたライセンスでした。条文は「自社の内部業務目的に限って使用できる」「ルールを配布したり、サービスとして他者に提供したりすることは認めない」としています。自社のCIで使う分には問題ありませんが、診断サービスや自社製品にルールを組み込んで提供する場合は該当します。
この変更を受けて生まれたのがフォークのOpengrepです(GitHubリポジトリの作成日は2024年12月14日・UTC)。READMEは「Semgrepが重要な機能を商用ライセンスの側へ移した」ことを理由に挙げ、Semgrep v1.100.0から分岐し、LGPL-2.1のまま、Windowsネイティブ対応や、同じファイル内で関数をまたぐtaint解析(--taint-intrafile)を追加しています。2026年10月7日時点の最新版は v1.30.2 です。CE版の検出範囲の制約を許容できず、かつ社外送信もできない場合の選択肢になります。
SonarQube・CodeQLとの使い分け
| 観点 | Semgrep | CodeQL | SonarQube |
|---|---|---|---|
| 主な用途 | 脆弱性・独自規約の検出 | 脆弱性の深い解析 | 品質とセキュリティの総合管理 |
| ルールの書き方 | 対象言語に近いYAML | 専用言語QL | 主に組み込みルール |
| 解析の前準備 | 不要(ファイルを直接解析) | CodeQLデータベースを生成 | スキャナー+サーバー |
| PHP・Scala | 対応 | 非対応 | 対応 |
| 無料の範囲 | CE・Free Edition | パブリックリポジトリ | Community Build |
※SemgrepのScalaは対応言語表で「Community rules」のみで、Semgrep社のPro rulesはありません。
判断の軸は「自分たちでルールを書くか」です。社内のコーディング規約や、過去に起きた不具合のパターンをその日のうちにルール化してCIで止めたいなら、Semgrepが最も手数が少なく済みます。前に示したルールは10行程度で、--test による回帰確認もルールと同じディレクトリにテストファイルを1つ置けば回せます。
GitHub上のプライベートリポジトリで、ライブラリをまたぐデータフローまで追いたい場合はCodeQLが候補です。プライベートリポジトリでの利用にはGitHub Code Security(1アクティブコミッターあたり月30ドル)が必要で、PHPとScalaは非対応です。CodeQLの設定手順はGitHub Code Scanningの記事で解説しています。コードの重複や複雑度、テストカバレッジまで含めた品質ゲートを置きたいならSonarQubeの機能と品質ゲートの設定、依存パッケージとコンテナの脆弱性が主眼ならSnykのCLIスキャンとCI組み込みやTrivyの使い方が向きます。
Semgrepを入れるべきでない場面もあります。ルールを書く担当者がおらず公開ルールセットを当てるだけになる場合、CE版では関数またぎの見逃しが残るうえ、検出結果をさばく人手だけが増えます。その状況なら、まずSonarQube CloudやGitHubのdefault setupのように、サーバー構築なしで結果画面まで揃う製品から始めるほうが定着します。シークレットの漏えい対策だけが目的なら、専用のgitleaksのほうが軽く導入できます。
よくある質問
Semgrepとは何ですか?
ソースコードを構文木として解析し、YAMLで書いたパターンに一致する脆弱性やバグを検出する静的解析ツールです。名前は「semantic grep」に由来し、エンジンのCommunity EditionはLGPL-2.1のオープンソースです。
Semgrepは無料で使えますか?
使えます。ローカルで動くCommunity Editionは無料で、人数の制限もありません。Semgrep社のクラウドを使うFree Editionも、10人・10リポジトリまで無料です。それを超える場合はTeams(Codeは1コントリビューターあたり月30ドル)になります。
Semgrepはどの言語に対応していますか?
Semgrep Codeは公式の対応言語表で35以上の言語に対応し、Python・Java・JavaScript・TypeScript・Go・C#・C/C++・Kotlinの8言語はファイルをまたぐ解析まで正式対応です。Supply Chain(依存関係の検査)は14言語です。
SemgrepとCodeQLの違いは何ですか?
Semgrepは対象言語に近い書き方のYAMLでルールを書き、ファイルを直接解析します。CodeQLはコードからデータベースを作り、専用言語QLで問い合わせます。CodeQLはPHPとScalaに非対応で、プライベートリポジトリではGitHub Code Securityの契約が必要です。
SemgrepはOWASP Top 10に対応していますか?
公開レジストリに p/owasp-top-ten というルールセットがあり、semgrep scan --config p/owasp-top-ten で実行できます。本記事のサンプル5ファイルに当てると152ルールが実行され、9件が検出されました。ただしTop 10の項目には認可設計のようにコードのパターンだけでは判定できないものも含まれるため、ルールセットを当てただけで対策済みとは言えません。各項目の内容はOWASP Top 10の最新版の解説を参照してください。