2026 年每日通報的 CVE 數量比前一年多 131%。

SBOM

開源 SBOM 產生工具遺漏了什麼

Syft、Trivy 與 cdxgen 功能強大、免費且廣受使用。三者都是從您指定的檔案建立 SBOM:鎖定檔(lockfile)、manifest 或已安裝的套件。這正是它們對同一個儲存庫結果不一致的原因,也是它們都看不到建置在這些檔案之外擷取了什麼的原因。

更新日期

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

每個工具只需一行指令,就能針對原始碼目錄或容器映像檔產出 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 目錄用的一組預設 cataloger,讀取宣告的相依套件 映像檔用的一組預設 cataloger,讀取已安裝的套件 cataloger 依掃描類型選定。syft cataloger list 會顯示哪些會執行,--select-catalogers 則可加入或移除。
Trivy lockfile;Node.js 為 package-lock.json、yarn.lock、pnpm-lock.yaml 與 bun.lock Node.js 為 package.json 檔案(位於 node_modules 底下) 除非您加上 --include-dev-deps,否則不包含開發用相依套件。
cdxgen 優先讀取 lockfile,包含開發用相依套件;Node.js 還會解析程式碼中的 import 支援 以 -t 設定專案類型,限制它要尋找的內容。

為什麼它們對同一個儲存庫的結果不一致

將三個工具都指向同一個 commit,您會得到三份不同的清單。它們都沒有故障,各自都依循自己文件記載的規則:

  • 沒有 lockfile,就沒有相依套件。Express 5.2.1 沒有提交 lockfile。在乾淨的 checkout 上,依 lockfile 或已安裝套件解析相依關係的工具兩者都沒有,因此 package.json 中宣告的 npm 相依套件永遠不會進入 SBOM。它仍會用它辨識到的其他內容,寫出一份有效的文件。
  • 已安裝或已宣告。掃描前是否執行過安裝,可能比使用哪個工具更重要。在同一個儲存庫的已安裝副本上,單一個 Syft cataloger 設定,就決定了已安裝的 npm 套件是否會出現。
  • 開發用相依套件。Trivy 預設排除,cdxgen 則會納入,因此同一個 lockfile 對「這個專案裡有什麼」會給出兩種答案。
  • 命名與版本。工具會以不同的 package URL 類型識別某些元件,或者一個工具將 GitHub Action 固定到 commit SHA,另一個卻回報標籤。以錯誤識別碼進行的漏洞查詢,會得到篤定卻錯誤的答案。
  • 完全沒有 manifest。anthropics/claude-code 儲存庫沒有相依套件 manifest,其 npm 套件包裝了一個預先建置的執行檔。各個工具回傳的結果,反映的是工具本身,而不是專案。

它們全都遺漏的:隱藏相依套件

更深層的限制是共通的。掃描工具讀取 lockfile 或建置的輸出,並在事後據此推斷放進了什麼。建置在這些檔案之外擷取的任何內容,都不會進入 SBOM。這些就是隱藏相依套件:

  • 安裝 hook。npm 的 preinstall 與 postinstall 腳本在安裝期間執行,能下載更多程式碼。Shai-Hulud 蠕蟲就是這樣執行的。
  • 建置腳本,例如會在建置時下載所需內容的 Rust 建置腳本。
  • 容器建置中的基礎映像檔及其作業系統層,任何語言的 lockfile 都不會列出。
  • 從 CI 快取還原的套件,可能與目前的 lockfile 不一致。請參閱 GitHub Actions 快取隱藏了什麼。
  • 由 setup 步驟安裝的建置工具,有它們自己的相依關係樹。
  • 當 lockfile 缺少、過時,或未被 frozen install 使用時,在建置時解析的遞移相依版本。請參閱遞移相依套件。

事後掃描輸出並無法彌補這個缺口。完成的執行檔,尤其是 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 版本,以及遭汙染的 trivy-action 與 setup-trivy 標籤,它們會從 CI 執行器竊取憑證。請將掃描工具的 action 固定到完整的 commit SHA,並對照公告檢查您執行的版本。

如何檢查您自己的 SBOM

  1. 對同一個 commit 執行兩個產生工具,並比較它們回報的 package URL。
  2. 檢查儲存庫是否提交了 lockfile,以及 CI 是否以 frozen install 從中安裝。
  3. 在安裝步驟之前與之後都進行掃描,並比較結果。
  4. 將清單與建置記錄中顯示的下載內容比較,包括 setup 步驟與快取還原。

如果清單不同,您發布的 SBOM 取決於您碰巧執行了哪個工具,而不是您實際交付了什麼。

改為記錄建置

CRACI 看得到流量,掃描工具則看不到。它是一個 GitHub Actions 執行器,能看到進入每次建置的網路流量,因此它的 SBOM 記錄了作業拉入的每個套件,涵蓋相依樹的每一層,包括隱藏相依套件與從 CI 快取還原的套件。不需要指定目錄,也不需要選擇 cataloger。當記錄無法看到全部內容時,例如作業允許了未受監控的流量,SBOM 會以其完整性狀態如實說明。

記錄之所以重要,也是因為建置很少能夠重現。將同一個 commit 連續建置兩次,套件管理工具可能以不同的順序解析與安裝,因此第二次建置可能包含不同的套件。只有在產出某個版本的那次建置中記錄的 SBOM,才能證明該版本包含什麼。

對於不是您建置的第三方映像檔與執行檔,請繼續使用 Syft 或 Trivy。對於您自己的版本,請參閱建置時 SBOM,或預約示範,在您的一個儲存庫上,將記錄下來的 SBOM 與您目前工具產出的 SBOM 比較。

開源 SBOM 產生工具:常見問題

產生 SBOM,Syft 和 Trivy 哪個比較好?

兩者是為不同工作而打造的。Syft 是專門的 SBOM 產生工具,有許多 cataloger 與簽署的證明;Trivy 是資安掃描工具,SBOM 只是它的輸出之一。兩者都讀取眼前的檔案,因此在同一個儲存庫上,較大的差異通常在於是否提交了 lockfile,以及掃描前是否安裝了相依套件。

為什麼我的 SBOM 沒有顯示任何相依套件?

最常見的原因是儲存庫沒有提交 lockfile,掃描前也沒有安裝任何東西。此時讀取 lockfile 或已安裝套件的產生工具沒有內容可讀,卻仍會寫出一份有效的 SBOM。請提交 lockfile,或在安裝步驟之後再掃描。

Trivy 的 SBOM 會包含開發用相依套件嗎?

預設不會。Trivy 的 Node.js 文件指出,除非加上 --include-dev-deps,否則它不會回報開發用相依套件。相較之下,cdxgen 會解析 lockfile 並納入開發用相依套件。光是這個原因,兩個工具就可能對同一個專案得出不同結果。

開源產生工具產出的 SBOM 可以信任嗎?

就它讀取的內容而言,可以。問題在於它沒有讀取的部分:快取、建置工具、下載內容、安裝腳本,以及沒有套件中繼資料的執行檔。請將掃描產生的 SBOM 視為對您指定檔案的描述,而不是對產出您版本之建置的描述。

最好的 SBOM 工具是什麼?

對於您自己建置的軟體,最完整的 SBOM 來自記錄建置,而不是掃描檔案。CRACI 記錄每個 GitHub Actions 作業擷取的每個套件,包括來自快取的套件,並曾找出 Snyk 與 Aikido 未回報的有漏洞套件。對於不是您建置的第三方映像檔與執行檔,Syft 或 Trivy 這類掃描工具仍是務實的選擇。

將記錄下來的 SBOM 與掃描工具的 SBOM 並列比較

在 CRACI 上執行一個 GitHub Actions 工作流程,並將它記錄已擷取套件的 SBOM,與 Syft、Trivy 或 cdxgen 回報的結果比較。

預約示範