以下の内容はhttps://kazuhira-r.hatenablog.com/entry/2025/11/03/203005より取得しました。


Semgrepでルールセットやルールを適用する

これは、なにをしたくて書いたもの?

Semgrepを扱ったこちらのエントリーの続きです。

SASTツール、Semgrep Community Editionを試す - CLOVER🍀

Semgrepを実行する際に指定するルールセットやルールの指定方法を見ていきます。

ルールセットやルールの指定方法

Semgrepに適用するルールセットやルールを指定するには、--configオプションを使います。

こんな感じですね。

$ semgrep scan --config p/default

Get started | Semgrep

Customize scans | Semgrep

これが基本です。

ルールセットというのは文字通りルールをまとめたものですが、ルールセット自体はSemgrepチームが管理していて、Semgrep Registryで
公開されます。

Rules can be organized in rulesets. Rulesets are rules related through a programming language, OWASP category, or framework. The rulesets are curated by the team at Semgrep and updated as new rules are added to the Semgrep Registry.

Run rules | Semgrep

ルールセットやルールはSemgrep Registryで探します。

Semgrep Registry / Explore

トップページに並んでいるのはルールセットですね。

Pythonのルールセット。

p/python

このように、言語やフレームワークなどでまとめられたルールセットがあります。

どのようなルールセットがあるのかを確認したい場合は、以下から見るとよいでしょう。「show all」で展開されます。

Semgrep Registry / r

含まれているルールも確認できます。Semgrep Community Editionを使う場合は、Visibilityを「Community (Public)」にして絞り込むと
よいでしょう。

個々のルールは展開すると見れます。

semgrepコマンドでの指定方法は、「Run locally」リンクをクリックすると表示されます。

こういう感じですね。

$ semgrep --config="r/python.aws-lambda.security.dangerous-asyncio-exec.dangerous-asyncio-exec"

つまり、ルールセットはp/[ルールセット名]、ルールはr/[ルール名]で指定することになりそうです。

Semgrep Registryの検索機能でルールを探してもいいでしょう。

ルールセットやルールなどを複数指定したい場合は、--configオプションを繰り返し指定します。
※指定しているルールはルールセットに含まれているので実質的な効果はありません

$ semgrep scan --config p/default --config p/python --config r/python.aws-lambda.security.dangerous-asyncio-exec.dangerous-asyncio-exec

Run rules / Run multiple rules simultaneously

環境変数SEMGREP_RULES指定することもできます。

$ SEMGREP_RULES=p/auto semgrep scan

Continuous integration (CI) environment variables / Environment variables for configuring scan behavior/ SEMGREP_RULES

複数指定する場合は、スペースで区切るようです。

$ SEMGREP_RULES='p/auto p/default' semgrep scan

ちなみに、除外するルールは--exclude-ruleオプションで指定します。

CLI reference | Semgrep

設定ファイル?

ところで、ルールがたくさんあると自分でルールセットというかプロジェクトごとに適用したいルールをまとめたくなる気がするのですが、
どうもそういう設定ができる気がしません。

出てくるのは、独自のルールの作り方です。

Run rules / Create and use local rules

Write rules

こういうのは、商用版であるSemgrep Codeを使ってUIで設定してもらう想定でいるのかなと思います。

Manage rules and policies | Semgrep

さて、どうしましょう。

semgrep-rulesをcloneして適用する

やり方のひとつとしては、semgrep-rulesリポジトリーをcloneして適用することでしょうか。

$ git clone https://github.com/semgrep/semgrep-rules

こんな感じで、--configオプションで指定すればOKです。

$ semgrep scan --config /path/to/semgrep-rules/generic --config /path/to/semgrep-rules/python

全部カスタムルールとして扱われていることになるんでしょうね。

なんとなく、用意されているルールセットで運用した方が楽な気がします…。

環境

今回確認した環境はこちら。

$ semgrep --version
1.142.0

オマケ:適用されているルールを確認する

こちらのエントリーで--debugオプションをつければ一時的にJSONファイルが出力されるので、それを見るとよさそう、みたいなことを
書きました。

$ semgrep --config auto --debug

SASTツール、Semgrep Community Editionを試す - CLOVER🍀

こういうのですね。

[00.05][INFO]: Parsing rules in /tmp/tmp_ja8xkz7.json
[00.23][DEBUG](default): read targets from file: /tmp/tmpwh0sugb5
[00.23][DEBUG](default): Core_scan.scan_exn { Core_scan_config.rule_source = Rule_file (/tmp/tmp_ja8xkz7.json);

試してみます。こういうコマンドを実行中に

$ semgrep scan --config p/python

生成されたJSONファイルを保存。

$ cat /tmp/*.json | tee python.json

ルールのidを出力してみます。

$ cat python.json | jq .rules[].id

こうなりました。

"python.boto3.security.hardcoded-token.hardcoded-token"
"python.cryptography.security.insecure-cipher-algorithms.insecure-cipher-algorithm-idea"
"python.cryptography.security.insecure-cipher-mode-ecb.insecure-cipher-mode-ecb"
"python.cryptography.security.insecure-hash-algorithms.insecure-hash-algorithm-sha1"
"python.cryptography.security.insufficient-dsa-key-size.insufficient-dsa-key-size"
"python.cryptography.security.insufficient-ec-key-size.insufficient-ec-key-size"
"python.cryptography.security.insufficient-rsa-key-size.insufficient-rsa-key-size"
"python.distributed.security.require-encryption"
"python.django.security.audit.avoid-insecure-deserialization.avoid-insecure-deserialization"
"python.django.security.injection.open-redirect.open-redirect"
"python.django.security.injection.reflected-data-httpresponse.reflected-data-httpresponse"
"python.django.security.injection.reflected-data-httpresponsebadrequest.reflected-data-httpresponsebadrequest"
"python.django.security.injection.request-data-fileresponse.request-data-fileresponse"
"python.django.security.injection.request-data-write.request-data-write"
"python.django.security.injection.code.user-eval-format-string.user-eval-format-string"
"python.django.security.injection.code.user-eval.user-eval"
"python.django.security.injection.code.user-exec-format-string.user-exec-format-string"
"python.django.security.injection.code.user-exec.user-exec"
"python.django.security.injection.command.command-injection-os-system.command-injection-os-system"
"python.django.security.injection.email.xss-html-email-body.xss-html-email-body"
"python.django.security.injection.email.xss-send-mail-html-message.xss-send-mail-html-message"
"python.django.security.injection.path-traversal.path-traversal-open.path-traversal-open"
"python.django.security.injection.sql.sql-injection-extra.sql-injection-using-extra-where"
"python.django.security.injection.sql.sql-injection-rawsql.sql-injection-using-rawsql"
"python.django.security.injection.sql.sql-injection-using-db-cursor-execute.sql-injection-db-cursor-execute"
"python.django.security.injection.sql.sql-injection-using-raw.sql-injection-using-raw"
"python.django.security.injection.ssrf.ssrf-injection-requests.ssrf-injection-requests"
"python.django.security.injection.ssrf.ssrf-injection-urllib.ssrf-injection-urllib"
"python.django.security.passwords.password-empty-string.password-empty-string"
"python.django.security.passwords.use-none-for-password-default.use-none-for-password-default"
"python.flask.security.audit.app-run-param-config.avoid_app_run_with_bad_host"
"python.flask.security.audit.app-run-security-config.avoid_using_app_run_directly"
"python.flask.security.audit.debug-enabled.debug-enabled"
"python.flask.security.audit.directly-returned-format-string.directly-returned-format-string"
"python.flask.security.injection.os-system-injection.os-system-injection"
"python.flask.security.injection.path-traversal-open.path-traversal-open"
"python.flask.security.injection.ssrf-requests.ssrf-requests"
"python.flask.security.injection.user-eval.eval-injection"
"python.flask.security.injection.user-exec.exec-injection"
"python.jwt.security.jwt-hardcode.jwt-python-hardcoded-secret"
"python.jwt.security.jwt-none-alg.jwt-python-none-alg"
"python.jwt.security.unverified-jwt-decode.unverified-jwt-decode"
"python.lang.security.insecure-hash-algorithms.insecure-hash-algorithm-sha1"
"python.lang.security.insecure-hash-function.insecure-hash-function"
"python.lang.security.unverified-ssl-context.unverified-ssl-context"
"python.lang.security.audit.ssl-wrap-socket-is-deprecated.ssl-wrap-socket-is-deprecated"
"python.lang.security.audit.subprocess-shell-true.subprocess-shell-true"
"python.lang.security.audit.weak-ssl-version.weak-ssl-version"
"python.lang.security.audit.insecure-transport.requests.request-session-http-in-with-context.request-session-http-in-with-context"
"python.lang.security.audit.insecure-transport.requests.request-session-with-http.request-session-with-http"
"python.lang.security.audit.insecure-transport.requests.request-with-http.request-with-http"
"python.lang.security.audit.logging.logger-credential-leak.python-logger-credential-disclosure"
"python.lang.security.audit.network.bind.avoid-bind-to-all-interfaces"
"python.lang.security.audit.network.disabled-cert-validation.disabled-cert-validation"
"python.lang.security.audit.network.http-not-https-connection.http-not-https-connection"
"python.lang.security.deserialization.avoid-pyyaml-load.avoid-pyyaml-load"
"python.lang.security.deserialization.avoid-unsafe-ruamel.avoid-unsafe-ruamel"
"python.lang.security.deserialization.pickle.avoid-shelve"
"python.pycryptodome.security.insecure-cipher-algorithm.insecure-cipher-algorithm-xor"
"python.pycryptodome.security.insecure-hash-algorithm.insecure-hash-algorithm-sha1"
"python.pycryptodome.security.insufficient-dsa-key-size.insufficient-dsa-key-size"
"python.pycryptodome.security.insufficient-rsa-key-size.insufficient-rsa-key-size"
"python.sqlalchemy.security.sqlalchemy-sql-injection.sqlalchemy-sql-injection"
"python.pymongo.security.mongodb.mongo-client-bad-auth"
"python.lang.security.audit.insecure-file-permissions.insecure-file-permissions"
"python.django.security.injection.raw-html-format.raw-html-format"
"python.flask.security.injection.raw-html-concat.raw-html-format"
"python.flask.security.injection.tainted-url-host.tainted-url-host"
"python.flask.security.injection.tainted-sql-string.tainted-sql-string"
"python.lang.security.audit.md5-used-as-password.md5-used-as-password"
"python.sqlalchemy.security.audit.avoid-sqlalchemy-text.avoid-sqlalchemy-text"
"python.aws-lambda.security.dangerous-asyncio-create-exec.dangerous-asyncio-create-exec"
"python.aws-lambda.security.dangerous-asyncio-exec.dangerous-asyncio-exec"
"python.aws-lambda.security.dangerous-asyncio-shell.dangerous-asyncio-shell"
"python.aws-lambda.security.dangerous-spawn-process.dangerous-spawn-process"
"python.aws-lambda.security.dangerous-subprocess-use.dangerous-subprocess-use"
"python.aws-lambda.security.dangerous-system-call.dangerous-system-call"
"python.aws-lambda.security.mysql-sqli.mysql-sqli"
"python.aws-lambda.security.psycopg-sqli.psycopg-sqli"
"python.aws-lambda.security.pymssql-sqli.pymssql-sqli"
"python.aws-lambda.security.pymysql-sqli.pymysql-sqli"
"python.aws-lambda.security.sqlalchemy-sqli.sqlalchemy-sqli"
"python.aws-lambda.security.tainted-code-exec.tainted-code-exec"
"python.aws-lambda.security.tainted-html-response.tainted-html-response"
"python.aws-lambda.security.tainted-sql-string.tainted-sql-string"
"python.django.security.nan-injection.nan-injection"
"python.flask.security.injection.nan-injection.nan-injection"
"python.aws-lambda.security.tainted-html-string.tainted-html-string"
"python.jinja2.security.audit.autoescape-disabled-false.incorrect-autoescape-disabled"
"python.jinja2.security.audit.missing-autoescape-disabled.missing-autoescape-disabled"
"python.aws-lambda.security.dynamodb-filter-injection.dynamodb-filter-injection"
"python.pyramid.audit.authtkt-cookie-httponly-unsafe-default.pyramid-authtkt-cookie-httponly-unsafe-default"
"python.pyramid.audit.authtkt-cookie-httponly-unsafe-value.pyramid-authtkt-cookie-httponly-unsafe-value"
"python.pyramid.audit.authtkt-cookie-samesite.pyramid-authtkt-cookie-samesite"
"python.pyramid.audit.authtkt-cookie-secure-unsafe-default.pyramid-authtkt-cookie-secure-unsafe-default"
"python.pyramid.audit.authtkt-cookie-secure-unsafe-value.pyramid-authtkt-cookie-secure-unsafe-value"
"python.pyramid.audit.csrf-origin-check-disabled-globally.pyramid-csrf-origin-check-disabled-globally"
"python.pyramid.audit.csrf-origin-check-disabled.pyramid-csrf-origin-check-disabled"
"python.pyramid.audit.set-cookie-httponly-unsafe-default.pyramid-set-cookie-httponly-unsafe-default"
"python.pyramid.audit.set-cookie-httponly-unsafe-value.pyramid-set-cookie-httponly-unsafe-value"
"python.pyramid.audit.set-cookie-samesite-unsafe-default.pyramid-set-cookie-samesite-unsafe-default"
"python.pyramid.audit.set-cookie-samesite-unsafe-value.pyramid-set-cookie-samesite-unsafe-value"
"python.pyramid.audit.set-cookie-secure-unsafe-default.pyramid-set-cookie-secure-unsafe-default"
"python.pyramid.audit.set-cookie-secure-unsafe-value.pyramid-set-cookie-secure-unsafe-value"
"python.pyramid.security.csrf-check-disabled-globally.pyramid-csrf-check-disabled-globally"
"python.pyramid.security.direct-use-of-response.pyramid-direct-use-of-response"
"python.pyramid.security.sqlalchemy-sql-injection.pyramid-sqlalchemy-sql-injection"
"python.aws-lambda.security.tainted-pickle-deserialization.tainted-pickle-deserialization"
"python.lang.security.audit.dangerous-asyncio-exec-tainted-env-args.dangerous-asyncio-exec-tainted-env-args"
"python.lang.security.audit.dangerous-asyncio-shell-tainted-env-args.dangerous-asyncio-shell-tainted-env-args"
"python.lang.security.audit.dangerous-code-run-tainted-env-args.dangerous-interactive-code-run-tainted-env-args"
"python.lang.security.audit.dangerous-os-exec-tainted-env-args.dangerous-os-exec-tainted-env-args"
"python.lang.security.audit.dangerous-spawn-process-tainted-env-args.dangerous-spawn-process-tainted-env-args"
"python.lang.security.audit.dangerous-subinterpreters-run-string-tainted-env-args.dangerous-subinterpreters-run-string-tainted-env-args"
"python.lang.security.audit.dangerous-subprocess-use-tainted-env-args.dangerous-subprocess-use-tainted-env-args"
"python.lang.security.audit.dangerous-system-call-tainted-env-args.dangerous-system-call-tainted-env-args"
"python.lang.security.audit.dangerous-testcapi-run-in-subinterp-tainted-env-args.dangerous-testcapi-run-in-subinterp-tainted-env-args"
"python.lang.security.dangerous-code-run.dangerous-interactive-code-run"
"python.lang.security.dangerous-os-exec.dangerous-os-exec"
"python.lang.security.dangerous-spawn-process.dangerous-spawn-process"
"python.lang.security.dangerous-subinterpreters-run-string.dangerous-subinterpreters-run-string"
"python.lang.security.dangerous-subprocess-use.dangerous-subprocess-use"
"python.lang.security.dangerous-system-call.dangerous-system-call"
"python.lang.security.dangerous-testcapi-run-in-subinterp.dangerous-testcapi-run-in-subinterp"
"python.django.security.injection.command.subprocess-injection.subprocess-injection"
"python.django.security.injection.csv-writer-injection.csv-writer-injection"
"python.flask.security.injection.csv-writer-injection.csv-writer-injection"
"python.flask.security.injection.subprocess-injection.subprocess-injection"
"python.cryptography.security.mode-without-authentication.crypto-mode-without-authentication"
"python.pycryptodome.security.mode-without-authentication.crypto-mode-without-authentication"
"python.cryptography.security.insecure-cipher-algorithms-arc4.insecure-cipher-algorithm-arc4"
"python.cryptography.security.insecure-cipher-algorithms-blowfish.insecure-cipher-algorithm-blowfish"
"python.cryptography.security.insecure-hash-algorithms-md5.insecure-hash-algorithm-md5"
"python.lang.security.insecure-hash-algorithms-md5.insecure-hash-algorithm-md5"
"python.pycryptodome.security.insecure-cipher-algorithm-blowfish.insecure-cipher-algorithm-blowfish"
"python.pycryptodome.security.insecure-cipher-algorithm-des.insecure-cipher-algorithm-des"
"python.pycryptodome.security.insecure-cipher-algorithm-rc2.insecure-cipher-algorithm-rc2"
"python.pycryptodome.security.insecure-cipher-algorithm-rc4.insecure-cipher-algorithm-rc4"
"python.pycryptodome.security.insecure-hash-algorithm-md2.insecure-hash-algorithm-md2"
"python.pycryptodome.security.insecure-hash-algorithm-md4.insecure-hash-algorithm-md4"
"python.pycryptodome.security.insecure-hash-algorithm-md5.insecure-hash-algorithm-md5"
"python.cryptography.security.empty-aes-key.empty-aes-key"
"python.django.security.hashids-with-django-secret.hashids-with-django-secret"
"python.flask.security.hashids-with-flask-secret.hashids-with-flask-secret"
"python.lang.security.use-defused-xml-parse.use-defused-xml-parse"
"python.django.security.django-using-request-post-after-is-valid.django-using-request-post-after-is-valid"
"python.fastapi.security.wildcard-cors.wildcard-cors"
"python.twilio.security.twiml-injection.twiml-injection"
"python.lang.security.insecure-uuid-version.insecure-uuid-version"
"python.lang.security.audit.sha224-hash.sha224-hash"
"python.flask.security.audit.flask-url-for-external-true.flask-url-for-external-true"

Semgrep Registryで見ればいいと思うのですが、もうちょっと簡単に一覧を確認できないでしょうか…。

オマケ: curlで確認する

Semgrep Registryのエンドポイントで確認できそうです。たとえばp/pythonの場合はこちら。

$ curl https://semgrep.dev/api/registry/rulesets/python

つまりhttps://semgrep.dev/api/registry/rulesets/[ルールセット名]ですね。

以下のようにすればルールのidに絞り込めます。

$ curl -s https://semgrep.dev/api/registry/rulesets/python | grep '^- id'

この方法で確認すると、Community Editionで使えるルールのみが得られるようです。

ブラウザから確認するとPro版の方も見れるので、なにか違いがあるんでしょうね(追いませんが…)。

おわりに

Semgrepでルールセットやルールを適用する方法を調べてみました。

ドキュメントに書いてあることは書いてあるのですが、なかなか全体を把握できなかったのでまとめてみた感じですね。

だいぶわかってきました。




以上の内容はhttps://kazuhira-r.hatenablog.com/entry/2025/11/03/203005より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14