2026年に報告されたCVEは、1日あたり前年比131%増加しています。

SBOM

オープンソースのSBOM生成ツールが見逃すもの

Syft、Trivy、cdxgenは高機能で無料、広く使われているツールです。3つとも、ロックファイル、マニフェスト、インストール済みパッケージなど、指定したファイルからSBOMを構築します。だからこそ同じリポジトリでも結果が食い違い、どれもそれらのファイル以外でビルドが取得したものを見ることができません。

更新日

What a scanner reads versus what the build pulled in A scanner reads the lockfile, which lists direct packages A, B and C and transitive packages D and E, so its SBOM contains only those. CRACI sees the network traffic into the build job, so its recorded SBOM also contains the hidden dependencies no lockfile lists: code downloaded by an install hook, a download by a build script, and the base image layers. A scanner reads the lockfile package-lock.json direct A B C transitive D E Scanned SBOM A, B, C, D, E only what the lockfile lists CRACI sees the traffic into the build A B C D E install hook download build script download base image layers build job on CRACI Recorded SBOM every package it fetched, hidden too Dashed: hidden dependencies, listed in no lockfile

各ツールでSBOMを生成する方法

どのツールも、ソースディレクトリまたはコンテナイメージに対して1つのコマンドを実行するだけで、CycloneDXまたはSPDXで出力できます。

# Syft: a source directory or a container image
syft ./my-project -o cyclonedx-json=sbom.cdx.json
syft my-image:latest -o spdx-json=sbom.spdx.json

# Trivy: a filesystem or a container image
trivy fs --format cyclonedx --output sbom.cdx.json .
trivy image --format spdx-json --output sbom.spdx.json my-image:latest

# cdxgen: the current directory, optionally with a project type
cdxgen -o bom.json .
cdxgen -t js -o bom.json .

コマンド自体は簡単です。ファイルに何が含まれるかは各ツールが何を読み取るかによって決まり、読み取る対象はツールごとに異なります。

各ツールが読み取るもの

ツール ソースディレクトリ コンテナイメージ 補足
Syft ディレクトリ用のデフォルトのカタロガー群。宣言された依存関係を読み取る イメージ用のデフォルトのカタロガー群。インストール済みパッケージを読み取る カタロガーはスキャンの種類によって選ばれます。syft cataloger listで実行されるものを確認でき、--select-catalogersで追加や削除ができます。
Trivy ロックファイル。Node.jsの場合はpackage-lock.json、yarn.lock、pnpm-lock.yaml、bun.lock Node.jsの場合はpackage.jsonファイル(node_modules配下) --include-dev-depsを指定しない限り、開発用の依存関係は含めません。
cdxgen まずロックファイル(開発用の依存関係を含む)。Node.jsではコードを解析してインポートも調べる 対応 -tでプロジェクトの種類を指定すると、探索対象を絞り込めます。

同じリポジトリで結果が食い違う理由

3つのツールを同じコミットに対して実行すると、3つの異なるリストが得られます。どれも壊れているわけではありません。それぞれが独自の文書化されたルールに従っています。

  • ロックファイルがなければ、依存関係もない。Express 5.2.1はロックファイルをコミットしていません。クリーンなチェックアウトでは、ロックファイルやインストール済みパッケージから依存関係を解決するツールにはそのどちらもないため、package.jsonで宣言されたnpmの依存関係はSBOMに入りません。それでも、他に認識できたものだけで有効なドキュメントを出力します。
  • インストール済みか、宣言のみか。スキャン前にインストールを実行したかどうかが、どのツールを使うかよりも大きく影響することがあります。同じリポジトリのインストール済みのコピーでは、Syftのカタロガー設定1つで、インストール済みのnpmパッケージがそもそも現れるかどうかが決まります。
  • 開発用の依存関係。Trivyはデフォルトで除外し、cdxgenは含めるため、同じロックファイルから「このプロジェクトに何が含まれるか」について2つの答えが得られます。
  • 名前とバージョン。ツールによって一部のコンポーネントを異なるパッケージURLタイプで識別したり、あるツールがタグを報告するGitHub Actionを別のツールはコミットSHAに固定したりします。誤った識別子で脆弱性を照合すると、もっともらしい誤った答えが返ってきます。
  • マニフェストがまったくない場合。anthropics/claude-codeリポジトリには依存関係のマニフェストがなく、そのnpmパッケージはビルド済みのバイナリをラップしています。各ツールが返す結果は、プロジェクトよりもツール自体について多くを語っています。

すべてが見逃すもの:隠れた依存関係

より根本的な限界は共通しています。スキャナーはロックファイルやビルドの出力を読み取り、そこから何が含まれたかを事後に割り出します。ビルドがそれらのファイル以外で取得したものは、SBOMに入りません。これが隠れた依存関係です。

  • インストールフック。npmのpreinstallとpostinstallスクリプトはインストール中に実行され、さらにコードをダウンロードできます。Shai-Huludワームもこの仕組みで動作しました。
  • ビルドスクリプト。たとえば、必要なものをビルド時にダウンロードするRustのビルドスクリプトです。
  • ベースイメージと、コンテナビルドにおけるそのOSレイヤー。どの言語のロックファイルにも記載されません。
  • CIキャッシュから復元されたパッケージ。現在のロックファイルと一致しない場合があります。GitHub Actionsのキャッシュが隠すものをご覧ください。
  • セットアップステップでインストールされるビルドツールと、それ自身の依存関係ツリー。
  • ビルド時に解決される推移的依存関係のバージョン。ロックファイルがない、古い、またはfrozenインストールで使われていない場合に発生します。推移的依存関係をご覧ください。

出力を後からスキャンしても、このギャップは埋まりません。完成したバイナリ、特にRustのようなコンパイル済みコードでは、スキャナーは何が含まれたかを推測するしかありません。商用のSCAスキャナーも同じ種類のファイルを起点に動作し、同じ死角を抱えています。CRACIは、SnykやAikidoが報告しなかった脆弱なパッケージを見つけています。それらのコンポーネントは、両ツールがスキャンした対象に一度も含まれていなかったからです。

Yoctoビルドにも同じ問題があります。SBOMスキャナーがYoctoビルドの中身を見逃す理由をご覧ください。

How a scanned SBOM and a recorded SBOM are made Left, a scanner: it reads the lockfile after the build, which lists packages A to E, so its SBOM contains A to E. The build also fetched code through an install hook, a build script download and a base image, which are in no lockfile, so the scanned SBOM is missing them. Right, CRACI: it sees the traffic coming into the build, so all eight packages, including the three hidden dependencies, land in the recorded SBOM. Scanner reads files after the build package-lock.json A B C D E the build also fetched install hook download build script download base image layers in no lockfile, so the scan never sees them Scanned SBOM A B C D E missing missing missing CRACI sees the traffic into the build the network build job on CRACI every package that comes in Recorded SBOM A B C D E install hook build script base image hidden ones too
A scanner can only list what the lockfile or the output declares. CRACI sees what actually came into the build, including the hidden dependencies.

ツールもサプライチェーンの一部

スキャナーはコードへのアクセス権、そして多くの場合シークレットへのアクセス権を持ってCI内で実行されます。2026年3月、Aqua Securityのアドバイザリ(CVE-2026-33634)は、悪意あるTrivy v0.69.4のリリースと、CIランナーから認証情報を盗む汚染されたtrivy-actionおよびsetup-trivyのタグについて説明しました。スキャナーのアクションは完全なコミットSHAで固定し、使用中のバージョンについてアドバイザリを確認してください。

自社のSBOMを確認する方法

  1. 同じコミットに対して2つの生成ツールを実行し、報告されたパッケージURLを比較する。
  2. リポジトリがロックファイルをコミットしているか、CIがfrozenインストールでそれを使ってインストールしているかを確認する。
  3. インストールステップの前と後の両方でスキャンし、比較する。
  4. セットアップステップやキャッシュの復元を含め、ビルドログにダウンロードとして記録されている内容とリストを比較する。

リストが異なる場合、公開するSBOMは、出荷したものではなく、たまたま実行したツールによって決まっていることになります。

代わりにビルドを記録する

CRACIは通信を見ており、スキャナーは見ていません。CRACIは各ビルドに入ってくるネットワーク通信を把握するGitHub Actionsランナーであり、そのSBOMは、隠れた依存関係やCIキャッシュから復元されたパッケージを含め、ジョブが取り込んだすべてのパッケージを依存関係ツリーのあらゆる階層で記録します。指定するディレクトリも、選ぶカタロガーもありません。たとえばジョブが監視対象外の通信を許可していたために記録がすべてを把握できなかった場合は、SBOMの完全性の状態がそのことを示します。

ビルドの再現性がほとんどないことも、記録が重要な理由です。同じコミットを続けて2回ビルドすると、パッケージマネージャーが異なる順序で解決・インストールすることがあり、2回目のビルドに異なるパッケージが含まれる可能性があります。リリースの内容を証明できるのは、そのリリースを生成したビルド中に記録されたSBOMだけです。

自社でビルドしていないサードパーティのイメージやバイナリには、引き続きSyftやTrivyを使ってください。自社のリリースについては、ビルド時SBOMをご覧いただくか、デモを予約して、自社のリポジトリの1つで記録したSBOMと現在のツールのSBOMを比較してください。

オープンソースのSBOM生成ツール:よくあるご質問

SBOMにはSyftとTrivyのどちらが適していますか?

両者は異なる用途のために作られています。Syftは多数のカタロガーと署名付きアテステーションを備えたSBOM専用の生成ツールで、TrivyはSBOMを出力の1つとして生成するセキュリティスキャナーです。どちらも目の前のファイルを読み取るため、同じリポジトリでは通常、ロックファイルがコミットされているか、スキャン前に依存関係がインストールされたかのほうが大きな違いを生みます。

SBOMに依存関係が1つも表示されないのはなぜですか?

多くの場合、リポジトリがロックファイルをコミットしておらず、スキャン前に何もインストールされていないためです。ロックファイルやインストール済みパッケージを読み取る生成ツールは読み取る対象がなく、それでも有効なSBOMを出力します。ロックファイルをコミットするか、インストールステップの後にスキャンしてください。

TrivyはSBOMに開発用の依存関係を含めますか?

デフォルトでは含めません。TrivyのNode.jsのドキュメントによれば、--include-dev-depsを指定しない限り、開発用の依存関係は報告されません。一方cdxgenはロックファイルを解析し、開発用の依存関係を含めます。この理由だけでも、2つのツールの結果が同じプロジェクトで食い違うことがあります。

オープンソースの生成ツールによるSBOMは信頼できますか?

読み取った範囲については信頼できます。問題は読み取らなかったもの、つまりキャッシュ、ビルドツール、ダウンロード、インストールスクリプト、パッケージメタデータのないバイナリです。スキャンによるSBOMは、リリースを生成したビルドではなく、ツールに指定したファイルを記述したものとして扱ってください。

最適なSBOMツールはどれですか?

自社でビルドするソフトウェアについては、ファイルをスキャンするのではなくビルドを記録することで、最も完全なSBOMが得られます。CRACIは、キャッシュからのものを含め、各GitHub Actionsジョブが取得するすべてのパッケージを記録し、SnykやAikidoが報告しなかった脆弱なパッケージを見つけています。自社でビルドしていないサードパーティのイメージやバイナリについては、SyftやTrivyのようなスキャナーが引き続き現実的な選択肢です。

記録したSBOMをスキャナーのSBOMと並べて比較

GitHub ActionsのワークフローをCRACIで1つ実行し、取得されたパッケージのSBOMを、Syft、Trivy、cdxgenが報告した内容と比較してください。

デモを予約