cicd-sensorによるライフサイクルスクリプト監視を試す
X-tech推進本部 黒澤先日、齋藤によるサプライチェーン攻撃対策 - 最低限見直すべき5つのポイントという記事を公開しました。齋藤の記事では今すぐ実施可能な対策も紹介していますので、まだお読みでないかたはぜひ、お読みください。
さて、サプライチェーン攻撃に限らず、対策を実施したあとは、対策が機能しているのか、すり抜けが生じているのかなどの確認も重要です。最近のサプライチェーン攻撃ではPCだけではなくCI/CD環境も狙われているため、この記事ではCI/CD環境向けの監視ツールであるcicd-sensorを検証しました。
検証の条件は次の通りです。
- GitHub ActionsのGitHub-hosted runnerで利用
- GitHub Actionsの再利用可能ワークフロー(cicd-sensor/cicd-sensor-action)経由で利用
- cicd-sensorのレポートはGitHub Actionsのartifactとして保存
長々と書きましたが、検証のために行ったことはワークフローにcicd-sensor/cicd-sensor-actionを追加したことのみです。
jobs:
build:
permissions:
contents: read
timeout-minutes: 5
runs-on: ubuntu-24.04
steps:
# ここから追加
- name: cicd-sensorのセットアップ
uses: cicd-sensor/cicd-sensor-action@777ddaafc9ec2e09c9779cdb860e75906adc19c2 # v0.0.34
# ここまで追加
- name: チェックアウト
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Node.jsのセットアップ
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: '24.17.0'
- name: 依存パッケージのインストール
run: npm ci
- name: ビルド
run: npm run build
インストール処理が子プロセスを立ち上げないことの検証
cicd-sensorはファイルアクセスやネットワーク通信なども監視できますが、今回はプロセスの監視を検証しました。
というのも、Node.jsエコシステムにおけるサプライチェーン攻撃ではpostinstallなどのライフサイクルスクリプトの悪用が続いているためです。ライフサイクルスクリプトはインストール処理(npm ciなど)の子プロセスとして実行されます。そのため、cicd-sensorでnpm ciの子プロセスを監視できるか検証しました。
cicd-sensorでは監視内容をYAMLファイルのルールとして記述できます。今回は親プロセスがnpm ciであるプロセスを収集するルールを作成しました(.cicd-sensor/rules/install.yml)
rule_sets:
- ruleset_id: test/install
rules:
- rule_id: npm_ci_no_child_processes
rule_name: "npm ciは子プロセスを実行しない"
event_type: process_exec
condition: |
process.ancestors.exists(parent,
parent.exec_path.endsWith("/node") &&
parent.argv.exists(arg, arg == "ci")
)
action: collect
なお、検証した環境ではnpmコマンドはnodeコマンドを実行するスクリプトへのリンクになっていたため、作成したルールではnpmコマンドではなくnodeコマンドを監視しています(parent.exec_path.endsWith("/npm")ではなくparent.exec_path.endsWith("/node")と記述)。
検証用にライフサイクルスクリプトをブロックしていないリポジトリを用意し、GitHub Actionsを実行した結果、cicd-sensorのレポートに子プロセスが記録されました。

/home/runner/actions-runner/cached/2.335.1/bin/Runner.Worker
"/home/runner<truncated, 60 bytes>" "spawnclient" "142" "145"
/usr/bin/bash
"/usr/bin/bas<truncated, 13 bytes>" "-e" "/home/runner<truncated, 63 bytes>"
/opt/hostedtoolcache/node/24.17.0/x64/bin/node
"node" "/opt/hostedt<truncated, 45 bytes>" "ci"
/usr/bin/sh pid: 2214
"sh" "-c" "node install<truncated, 38 bytes>"
調べてみると、このプロセスは画像処理ライブラリーとして有名なsharpのinstallスクリプトでした。検証した環境ではinstallスクリプトを実行しなくてもoptionalDependencies経由でバイナリーをインストールできますので、ライフサイクルスクリプトの実行をブロックするように.npmrcを調整しました。
ignore-scripts=true
ライフサイクルスクリプトをブロックした状態で再度GitHub Actionsを実行すると子プロセスは記録されませんでした。
また、cicd-sensorでは記録だけではなく処理をブロックすることもできます。具体的にはルール内のactionをterminateに変更します。
rule_sets:
- ruleset_id: test/install
rules:
- rule_id: npm_ci_no_child_processes
rule_name: "npm ciは子プロセスを実行しない"
event_type: process_exec
condition: |
process.ancestors.exists(parent,
parent.exec_path.endsWith("/node") &&
parent.argv.exists(arg, arg == "ci")
)
# ここから変更
action: terminate
# ここまで変更
この状態で、GitHub Actionsを実行するとnpm ciのステップが失敗することを確認できました。

Run npm ci
Error: Process completed with exit code 130.
まとめ
この記事ではcicd-sensorを使ったCI/CD環境の監視を検証しました。
cicd-sensorは手軽に導入でき、現実的なルールも記述できることがわかりました。
組織的に監視するには、ルールの整備・配布、ログの保存・確認などが必要ですが、まずは現状把握として試してみてはいかがでしょうか。