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

SBOM

SBOM 應該描述實際出貨的那次建置

建置時 SBOM 是在建置執行期間,依據實際進入建置的流量記錄而成。多數 SBOM 產生工具則是在事後從鎖定檔(lockfile)或建置產出重建清單,因而漏掉建置自行取得的隱藏相依套件。以下說明原因,以及記錄建置會帶來哪些改變。

更新日期

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

Build SBOM、Source SBOM 與 Analyzed SBOM

CISA 關於 SBOM 類型的指引,依製作的時機與方式將 SBOM 分類。其中三種涵蓋了目前幾乎所有使用中的 SBOM 產生工具:

類型 製作方式 可能遺漏的內容
Source 從原始碼檔案、manifest 與鎖定檔產生,通常由 SCA 工具製作 執行期、外掛或平台元件;任何未在檔案中宣告的內容
Build 在產生可發布建置產物的建置過程中製作 建置環境看不到的任何內容,這也是為什麼應該標示完整性
Analyzed 在建置之後,透過分析可執行檔、套件或容器映像檔製作 工具無法辨識的元件;結果取決於啟發式規則

CISA 列出 Build SBOM 的兩項優點:由於建置與 CI/CD 流程中可取得的資訊,更能確信 SBOM 正確代表建置產物;以及由於同一個建置工作流程可同時簽署 SBOM 與建置產物,因此更值得信賴。它所列的缺點是,您可能必須修改建置流程才能產生 SBOM。使用 CRACI,這項修改只有一行:runs-on: craci,記錄功能隨執行器一併提供。

掃描資料夾與記錄建置的差異

多數 SBOM 產生工具都是掃描工具。您將它指向原始碼樹或容器映像檔,它就會透過讀取 manifest、鎖定檔、已安裝的套件或二進位檔,推斷其中可能包含哪些內容。這很實用,而對於並非您自行建置的軟體,這往往是唯一的選擇。

它的弱點在於,掃描工具只看得到眼前的東西。如果沒有提交鎖定檔、掃描前沒有先安裝相依套件,或產品以編譯後的二進位檔出貨,掃描工具可用的資訊就比建置時少。即使掃描完全找不到任何元件,仍會產生一份有效的 SBOM 文件,而這正是讓人措手不及的地方。

CRACI 採取不同的做法。它在自己的 CI 執行器內產生 SBOM,因此出貨的建置產物就是 SBOM 所描述的建置產物,而不是在附近某處執行的一次掃描。

SBOM basics: SPDX, CycloneDX and OpenVEX

SBOM 記錄了哪些內容、SPDX 與 CycloneDX 格式在實務上有何不同,以及 OpenVEX 如何補充說明某個漏洞是否真的影響產品。

Petteri Pulkkinen和Erika Marttinen 於 Kubernetes Community Days Helsinki 2026,SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains 的 16:50 至 22:05。

掃描取決於什麼

Syft、Trivy、cdxgen、Microsoft SBOM Tool、GitHub 的相依關係圖匯出,以及 Socket CLI,都是從它們能讀取的內容推算出 SBOM。以下這些模式,源自這些工具文件中所記載的運作方式。

各工具對於什麼算是元件看法不一

每個產生工具都自行決定什麼算是元件、要信任哪些檔案,因此同一個固定的 commit,會讓每個工具產出不同的清單。

其中一部分是命名問題。各工具會以不同的套件 URL 類型識別同一個 GitHub Action,因此即使列出的是同一個東西,也可能無法對應。這本身也是問題的一部分:對元件使用不同識別碼的 SBOM,更難與漏洞資料比對。

是否先安裝,可能比選用哪個工具更重要

Express 5.2.1 並未提交鎖定檔。若將工具指向乾淨的 checkout,一個從鎖定檔或已安裝套件樹解析相依套件的產生工具,面前兩者皆無,因此 package.json 中宣告的 npm 相依套件,沒有一個會出現在文件中。它仍可能回傳一份清單,由它辨識出的其他內容組成,例如 GitHub Actions 以及引用它們的工作流程檔案。這裡沒有任何工具是壞掉的。

在同一個儲存庫已安裝的副本上,一個 Syft 旗標就會再次改變答案。同一個工具、同一個目錄樹、同一個版本。依其設計,Syft 的目錄掃描回報的是專案所宣告的內容,而讀取已安裝套件的 cataloger 並不在其目錄掃描的預設組合中。

有些軟體根本沒有 manifest 可讀

anthropics/claude-code 儲存庫在 v2.1.259 版沒有任何形式的相依套件 manifest:沒有 package.json、鎖定檔或同等的檔案。每個產生工具為它回傳的內容,都是從其他檔案類型拼湊而來,因此答案反映的是工具本身,而不是專案。

已發布的 npm 套件也差不多。@anthropic-ai/claude-code 宣告的執行期相依套件為零,另有八個包裝預先編譯二進位檔的平台專用套件。 @openai/codex 0.149.1 也是相同的結構。在開發者機器上執行的是編譯後的二進位檔,任何 manifest 讀取工具都無法看進其中。這不是任何單一工具的缺陷,而是一種事後掃描無法描述的發布模式。

版本與供應商

即使兩個工具找到同一個套件,它們對其版本也不一定看法一致。一個可能將 GitHub Action 固定在某個 commit SHA,另一個則回報版本標籤。以錯誤版本查詢漏洞,會得到一個信心十足卻錯誤的答案。

供應商欄位是 NTIA 最低要素之一,卻經常是空白的,因為多數產生工具都沒有這項資訊的來源。

隱藏相依套件:任何掃描都看不到的內容

上述每個工具都是從鎖定檔或建置產出出發,推算出其中包含了什麼。但建置取用的內容不只這些。這些隱藏相依套件沒有列在任何鎖定檔中,因此掃描找不到它們:

  • 安裝鉤子。npm 的 preinstall 與 postinstall 腳本會在安裝期間執行,並可能下載更多程式碼。Shai-Hulud 蠕蟲就是這樣運作的。
  • 建置腳本。Rust 的建置腳本等,會在建置時下載所需的內容。
  • 基礎映像檔。容器建置會拉取基礎映像檔及其作業系統層,而這些不會列在任何程式語言的鎖定檔中。
  • 快取與建置工具。從 CI 快取還原的套件,以及由 setup 步驟安裝的工具,同樣是在鎖定檔之外進入建置。

事後掃描建置產出並不能補上這個缺口。完成的二進位檔,尤其是 Rust 這類編譯後的程式碼,只能讓掃描工具去猜測其中包含了什麼。

兩次建置,兩份 SBOM

掃描無法代替建置還有第二個原因:多數建置都不是可重現的。同一個 commit 連續建置兩次,並不保證會得到相同的套件。套件管理工具會依回應抵達的順序解析與安裝,這在沒有鎖定檔時影響最大(許多 Python 專案就是如此),而建置步驟本身也可能包含隨機性。逐位元組可重現的建置是可行的,例如使用 Nix 等工具,但相當少見。

因此,事後在另一台機器上或從另一次建置產生的 SBOM,描述的可能是一個從未出貨的建置。只有在產生版本的那次 CI 建置期間記錄的 SBOM,才能證明正式環境中有什麼。

記錄建置帶來的改變

CRACI 看得到流量,掃描工具則看不到。它在自己的執行器上執行您的 GitHub Actions 作業,並看到進入每次建置的網路流量,因此 SBOM 列出的是作業實際拉取的內容(包括遞移與隱藏相依套件),而不是 manifest 宣稱所需的內容。

快取是建置時記錄的難處所在。從快取還原的套件從不接觸套件庫(registry),因此單靠代理伺服器會漏掉它。CRACI 會讓相依套件的佐證資料隨快取一起傳遞,因此從快取還原的套件,會留在還原它的那個作業的 SBOM 中。請參閱 GitHub Actions 快取隱藏了什麼。

可偵測的生態系包括 npm、PyPI、RubyGems、Cargo、Go、Nix、OCI、apt、apk 與 Git 來源,以及 Yocto 與 OpenEmbedded 的下載預設組態。JFrog Artifactory 的 npm 與 PyPI 鏡像也能運作。宣告的授權中繼資料會包含在匯出中。SBOM 可匯出為 CycloneDX 與 SPDX。完整功能請參閱 SBOM 產生頁面。

看得到流量,在另一個方向也同樣有用。建置需要從已知來源取得套件,並將產出發布到已知位置。CRACI 的對外連線政策只允許這些連線,並立即封鎖其他所有對外連線,因此試圖將您的機密傳送到攻擊者伺服器的惡意軟體會失敗。由於這項政策是允許建置所需的連線,而不是尋找已知的惡意主機,因此即使您是一場前所未見的攻擊的第一個目標(例如 Shai-Hulud),它依然有效。請參閱 對外連線政策如何阻止資料外洩。

容器與 Docker SBOM

容器映像檔是差異最明顯的地方。取得 Docker SBOM 的常見方式都是分析映像檔:Syft 與 Trivy 會掃描映像檔,docker scout sbom 在映像檔未附 SBOM 證明時會為其內容建立索引,而以 --sbom=true 啟用的 BuildKit SBOM 證明,預設會對最終的映像檔階段執行以 Syft 為基礎的掃描工具。較舊的 docker sbom 外掛已棄用,建議改用 docker scout sbom。

這些方式讀取的都是完成的映像檔,因此只看得到在各層中仍可辨識的內容,看不到建置過程中取用的內容。CRACI 記錄的是建置映像檔的那個作業:作業從 OCI 套件庫與套件來源拉取的映像檔與套件,會與建置的其他部分一起列入同一份 SBOM。對於並非您自行建置的映像檔,掃描仍是實際可行的選擇。請參閱Docker 映像檔 SBOM 遺漏了什麼。

每個作業標示完整性

記錄而成的 SBOM,品質取決於記錄本身。CRACI 不會把每份 SBOM 都呈現為完整,而是為每個作業與每個快取標示完整性,分為以下五種狀態之一:

  • Complete。CRACI 觀察到完整的作業佐證資料,且每個還原的快取都是完整的。
  • Complete with connections。已通過各項要求,但作業使用了一個或多個自訂網路連線,因此值得檢查透過這些連線傳入的內容。
  • Incomplete。CRACI 發現了可能讓相依套件未列入 SBOM 的狀況。
  • Unavailable。CRACI 無法完成佐證資料的評估。
  • Not recorded。該作業早於完整性回報功能推出之前。

完整性會跨快取傳遞。如果作業還原了不完整的快取,其 SBOM 也會是不完整的,而該作業產生的任何快取都會延續這個不完整狀態。您可以清楚知道哪些 SBOM 可以信賴,哪些需要再檢查一次。

The hard parts: hooks, noise and staying current

演講點出的三個問題:post-install 鉤子會取得任何 manifest 都未列出的內容、要在一長串清單中找出真正重要的相依套件,以及讓 SBOM 保持最新,也就是在每次建置時都於 CI 中產生 SBOM。

Petteri Pulkkinen和Erika Marttinen 於 Kubernetes Community Days Helsinki 2026,SBOMbastic: Getting Ready for Upcoming EU Cybersecurity Regulation in Software Supply Chains 的 25:39 至 27:22。

透過 API 取得來源證明

SBOM 只是 CRACI 為每個作業記錄的內容之一。API 會回傳 SBOM、網路追蹤記錄與來源證明(provenance),全部記錄自同一次建置。

掃描工具仍是正確選擇的情況

建置時記錄涵蓋的是您所建置的軟體。對於並非您自行建置的第三方映像檔或二進位檔,掃描工具仍是實際可行的選擇,而上述工具都相當強大且廣受使用。重點不在於掃描工具不好,而在於您自己版本的 SBOM,應該來自產生這些版本的建置。

CRACI 的 SBOM 也有其自身的限制。它涵蓋在 CRACI 執行器上執行的作業,目前也就是 Linux 上的 GitHub Actions,其他 CI 系統已列入產品藍圖。

正在比較工具嗎?請參閱SBOM 工具比較,或了解建置時 SBOM 如何融入CRA 法規遵循工作。Syft、Trivy 與 cdxgen 的並列比較,請參閱 開源 SBOM 產生工具遺漏了什麼。

建置時 SBOM:常見問題

什麼是建置時 SBOM?

建置時 SBOM(CISA 稱為 Build SBOM)是在建置可發布建置產物的過程中產生的。它不是事後從檔案重建元件清單,而是描述建置本身使用了什麼。CRACI 依據每個 GitHub Actions 作業實際取用的套件記錄而成。

Build SBOM 與 Analyzed SBOM 有何不同?

Analyzed SBOM 是在建置之後,透過分析可執行檔或容器映像檔等建置產物而產生,通常需要依賴啟發式規則。Build SBOM 則是在建置期間,依據建置所掌握的資訊產生。Analyzed SBOM 不需要存取建置就能運作,因此是並非您自行建置之軟體的正確選擇。

如何為 Docker 映像檔產生 SBOM?

對於既有的映像檔,可使用 Syft、Trivy 或 docker scout sbom 等產生工具進行掃描。BuildKit 也能在建置時透過掃描最終映像檔,附加 SBOM 證明。若要記錄映像檔建置拉取了哪些內容,請在 CRACI 執行器上執行建置:該作業的 SBOM 會涵蓋其取用的映像檔與套件。

什麼是隱藏相依套件?

建置取用、但沒有任何鎖定檔列出的所有內容:npm 安裝鉤子下載的程式碼、Rust 建置腳本在建置時下載的檔案,以及容器建置中的基礎映像檔及其作業系統層。讀取鎖定檔或掃描建置產出的工具都會漏掉它們。CRACI 之所以能記錄它們,是因為它看得到進入建置的流量。

為什麼同一份程式碼建置兩次,會得到不同的 SBOM?

因為多數建置都不是可重現的。套件管理工具會依回應抵達的順序解析與安裝套件,在沒有鎖定檔時尤其如此,而建置步驟也可能包含隨機性。同一個 commit 連續建置兩次,第二次建置可能包含不同的套件。只有在產生版本的那次建置期間記錄的 SBOM,才能證明該版本包含了什麼。

建置時 SBOM 一定是完整的嗎?

並非必然。記錄的品質取決於它能觀察到的內容,因此 CRACI 會為每個作業與每個快取標示完整性:Complete、Complete with connections、Incomplete、Unavailable 或 Not recorded。您可以清楚知道哪些 SBOM 可以信賴,哪些需要再檢查一次。

建置時 SBOM 會取代 SBOM 掃描工具嗎?

就您所建置的軟體而言,是的:您版本的 SBOM 應該來自產生這些版本的建置。對於並非您自行建置的第三方映像檔與二進位檔,掃描工具仍是實際可行的選擇。SBOM 工具比較介紹了各種選項。

CRACI 使用哪一種 SBOM 產生工具?

都沒有。CRACI 不掃描檔案。其執行器上具備套件感知能力的代理伺服器,會記錄每個作業從 npm、PyPI、RubyGems、Cargo、Go、Nix、OCI、apt、apk 與 Git 來源,以及 Yocto 與 OpenEmbedded 下載預設組態取用的套件,並將結果匯出為 CycloneDX 或 SPDX。

比較您自己建置的 SBOM

預約示範,在 CRACI 上執行您的一個工作流程。將它的 SBOM 與您目前工具產生的 SBOM 並列,看看差異在哪裡。

預約示範