analyzing-sbom-for-supply-chain-vulnerabilities
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAnalyzing SBOM for Supply Chain Vulnerabilities
分析SBOM以识别供应链漏洞
When to Use
适用场景
- A new regulatory requirement (EO 14028, EU CRA) mandates SBOM analysis for software deliveries
- Security team needs to assess third-party risk by scanning vendor-provided SBOMs
- CI/CD pipeline requires automated vulnerability checks against generated SBOMs
- Incident response needs to determine if a newly disclosed CVE affects deployed software
- Procurement team requires supply chain risk assessment for a software acquisition
Do not use for runtime vulnerability scanning of live systems; use container scanning tools (Trivy, Grype CLI) or host-based vulnerability scanners (Nessus, Qualys) instead.
- 新的监管要求(EO 14028、EU CRA)强制要求对软件交付物进行SBOM分析
- 安全团队需要通过扫描供应商提供的SBOM评估第三方风险
- CI/CD流水线需要针对生成的SBOM执行自动化漏洞检查
- 事件响应需要确定新披露的CVE是否影响已部署的软件
- 采购团队需要对软件采购进行供应链风险评估
请勿用于实时系统的运行时漏洞扫描;请改用容器扫描工具(Trivy、Grype CLI)或基于主机的漏洞扫描器(Nessus、Qualys)。
Prerequisites
前提条件
- SBOM file in CycloneDX JSON (v1.4+) or SPDX JSON (v2.3+) format
- Python 3.9+ with requests, networkx, and packaging libraries installed
- NVD API key (free, from https://nvd.nist.gov/developers/request-an-api-key) for higher rate limits
- Network access to NVD API (https://services.nvd.nist.gov/rest/json/cves/2.0)
- Optionally: syft for SBOM generation, grype for cross-validation
- CycloneDX JSON(v1.4+)或SPDX JSON(v2.3+)格式的SBOM文件
- 已安装requests、networkx和packaging库的Python 3.9+环境
- NVD API密钥(免费获取,地址:https://nvd.nist.gov/developers/request-an-api-key),用于提高请求速率限制
- 可访问NVD API(https://services.nvd.nist.gov/rest/json/cves/2.0)的网络环境
- 可选:用于生成SBOM的syft,用于交叉验证的grype
Workflow
工作流程
Step 1: Generate SBOM (if not provided)
步骤1:生成SBOM(若未提供)
Use syft to create an SBOM from a container image or project directory:
bash
undefined使用syft从容器镜像或项目目录生成SBOM:
bash
undefinedGenerate CycloneDX JSON from a container image
Generate CycloneDX JSON from a container image
syft alpine:latest -o cyclonedx-json > sbom-cyclonedx.json
syft alpine:latest -o cyclonedx-json > sbom-cyclonedx.json
Generate SPDX JSON from a project directory
Generate SPDX JSON from a project directory
syft dir:/path/to/project -o spdx-json > sbom-spdx.json
syft dir:/path/to/project -o spdx-json > sbom-spdx.json
Generate from a running container
Generate from a running container
syft docker:my-app-container -o cyclonedx-json > sbom.json
Syft supports over 30 package ecosystems including npm, PyPI, Maven, Go modules, apt, apk, and RPM. The generated SBOM includes package names, versions, licenses, CPE identifiers, and PURL (Package URL) references.syft docker:my-app-container -o cyclonedx-json > sbom.json
Syft支持超过30种包生态系统,包括npm、PyPI、Maven、Go模块、apt、apk和RPM。生成的SBOM包含包名称、版本、许可证、CPE标识符和PURL(包URL)引用。Step 2: Parse SBOM and Extract Components
步骤2:解析SBOM并提取组件
Parse the SBOM to extract all software components with their identifiers:
CycloneDX JSON Structure:
json
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"components": [
{
"type": "library",
"name": "lodash",
"version": "4.17.20",
"purl": "pkg:npm/lodash@4.17.20",
"cpe": "cpe:2.3:a:lodash:lodash:4.17.20:*:*:*:*:*:*:*",
"licenses": [{"license": {"id": "MIT"}}]
}
],
"dependencies": [
{"ref": "pkg:npm/express@4.18.2", "dependsOn": ["pkg:npm/lodash@4.17.20"]}
]
}SPDX JSON Structure:
json
{
"spdxVersion": "SPDX-2.3",
"packages": [
{
"name": "lodash",
"versionInfo": "4.17.20",
"externalRefs": [
{"referenceType": "purl", "referenceLocator": "pkg:npm/lodash@4.17.20"},
{"referenceType": "cpe23Type", "referenceLocator": "cpe:2.3:a:lodash:lodash:4.17.20:*:*:*:*:*:*:*"}
],
"licenseConcluded": "MIT"
}
],
"relationships": [
{"spdxElementId": "SPDXRef-express", "relatedSpdxElement": "SPDXRef-lodash",
"relationshipType": "DEPENDS_ON"}
]
}解析SBOM以提取所有带标识符的软件组件:
CycloneDX JSON结构:
json
{
"bomFormat": "CycloneDX",
"specVersion": "1.5",
"components": [
{
"type": "library",
"name": "lodash",
"version": "4.17.20",
"purl": "pkg:npm/lodash@4.17.20",
"cpe": "cpe:2.3:a:lodash:lodash:4.17.20:*:*:*:*:*:*:*",
"licenses": [{"license": {"id": "MIT"}}]
}
],
"dependencies": [
{"ref": "pkg:npm/express@4.18.2", "dependsOn": ["pkg:npm/lodash@4.17.20"]}
]
}SPDX JSON结构:
json
{
"spdxVersion": "SPDX-2.3",
"packages": [
{
"name": "lodash",
"versionInfo": "4.17.20",
"externalRefs": [
{"referenceType": "purl", "referenceLocator": "pkg:npm/lodash@4.17.20"},
{"referenceType": "cpe23Type", "referenceLocator": "cpe:2.3:a:lodash:lodash:4.17.20:*:*:*:*:*:*:*"}
],
"licenseConcluded": "MIT"
}
],
"relationships": [
{"spdxElementId": "SPDXRef-express", "relatedSpdxElement": "SPDXRef-lodash",
"relationshipType": "DEPENDS_ON"}
]
}Step 3: Correlate Components with NVD CVE Database
步骤3:将组件与NVD CVE数据库关联
Query the NVD 2.0 API to find known vulnerabilities for each component:
python
import requests
NVD_API = "https://services.nvd.nist.gov/rest/json/cves/2.0"
def search_cves_by_cpe(cpe_name, api_key=None):
params = {"cpeName": cpe_name, "resultsPerPage": 50}
headers = {"apiKey": api_key} if api_key else {}
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("vulnerabilities", [])
def search_cves_by_keyword(keyword, version=None, api_key=None):
params = {"keywordSearch": keyword, "resultsPerPage": 50}
headers = {"apiKey": api_key} if api_key else {}
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("vulnerabilities", [])The NVD API supports searching by CPE name (most precise), keyword, CVE ID, and date ranges. Rate limits: 5 requests/30 seconds without API key, 50 requests/30 seconds with key.
查询NVD 2.0 API以查找每个组件的已知漏洞:
python
import requests
NVD_API = "https://services.nvd.nist.gov/rest/json/cves/2.0"
def search_cves_by_cpe(cpe_name, api_key=None):
params = {"cpeName": cpe_name, "resultsPerPage": 50}
headers = {"apiKey": api_key} if api_key else {}
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("vulnerabilities", [])
def search_cves_by_keyword(keyword, version=None, api_key=None):
params = {"keywordSearch": keyword, "resultsPerPage": 50}
headers = {"apiKey": api_key} if api_key else {}
resp = requests.get(NVD_API, params=params, headers=headers, timeout=30)
resp.raise_for_status()
return resp.json().get("vulnerabilities", [])NVD API支持按CPE名称(最精确)、关键字、CVE ID和日期范围进行搜索。速率限制:无API密钥时为30秒5次请求,有密钥时为30秒50次请求。
Step 4: Build Dependency Graph and Identify Transitive Risks
步骤4:构建依赖图并识别传递性风险
Construct a directed graph of dependencies to trace vulnerability propagation:
python
import networkx as nx
def build_dependency_graph(sbom):
G = nx.DiGraph()
# Add nodes for each component
for comp in sbom["components"]:
G.add_node(comp["purl"], name=comp["name"], version=comp["version"])
# Add edges from dependency relationships
for dep in sbom.get("dependencies", []):
for child in dep.get("dependsOn", []):
G.add_edge(dep["ref"], child)
return GTransitive dependency analysis identifies components that are not directly included but are pulled in through dependency chains. A vulnerability in a deeply nested transitive dependency (e.g., 4 levels deep) still represents risk but may be harder to remediate.
Key graph metrics for risk assessment:
- In-degree: How many components depend on this one (high in-degree = high blast radius)
- Shortest path to root: Distance from application entry point (closer = more exploitable)
- Betweenness centrality: Components that sit on many dependency paths (bottleneck risk)
构建依赖有向图以追踪漏洞传播路径:
python
import networkx as nx
def build_dependency_graph(sbom):
G = nx.DiGraph()
# Add nodes for each component
for comp in sbom["components"]:
G.add_node(comp["purl"], name=comp["name"], version=comp["version"])
# Add edges from dependency relationships
for dep in sbom.get("dependencies", []):
for child in dep.get("dependsOn", []):
G.add_edge(dep["ref"], child)
return G传递性依赖分析可识别未直接包含但通过依赖链引入的组件。深度嵌套的传递性依赖(例如4层深)中的漏洞仍存在风险,但可能更难修复。
风险评估的关键图指标:
- 入度:有多少组件依赖于此组件(入度高=影响范围大)
- 到根节点的最短路径:与应用入口点的距离(越近=越易被利用)
- 介数中心性:位于许多依赖路径上的组件(瓶颈风险)
Step 5: Calculate Risk Scores
步骤5:计算风险评分
Aggregate vulnerability data into component and overall risk scores:
Risk Score Calculation:
━━━━━━━━━━━━━━━━━━━━━━
Component Risk = max(CVSS scores of all CVEs affecting the component)
Weighted Risk = Component Risk * Dependency Factor
where Dependency Factor = 1.0 + (0.1 * in_degree)
(more dependents = higher organizational impact)
Overall SBOM Risk = weighted average of all component risks
weighted by dependency centrality
Risk Levels:
CRITICAL: CVSS >= 9.0 or known exploited (CISA KEV)
HIGH: CVSS >= 7.0
MEDIUM: CVSS >= 4.0
LOW: CVSS < 4.0将漏洞数据汇总为组件和整体风险评分:
风险评分计算:
━━━━━━━━━━━━━━━━━━━━━━
组件风险 = 影响该组件的所有CVE的最高CVSS评分
加权风险 = 组件风险 × 依赖因子
其中依赖因子 = 1.0 + (0.1 × 入度)
(依赖者越多=组织影响越大)
整体SBOM风险 = 所有组件风险的加权平均值
按依赖中心性加权
风险等级:
严重:CVSS >= 9.0 或已被利用(CISA KEV)
高:CVSS >= 7.0
中:CVSS >= 4.0
低:CVSS < 4.0Step 6: Cross-Validate with Grype
步骤6:使用Grype交叉验证
Use grype to independently scan the SBOM and compare findings:
bash
undefined使用grype独立扫描SBOM并对比结果:
bash
undefinedScan CycloneDX SBOM with grype
Scan CycloneDX SBOM with grype
grype sbom:sbom-cyclonedx.json -o json > grype-results.json
grype sbom:sbom-cyclonedx.json -o json > grype-results.json
Scan SPDX SBOM
Scan SPDX SBOM
grype sbom:sbom-spdx.json -o table
grype sbom:sbom-spdx.json -o table
Filter by severity
Filter by severity
grype sbom:sbom-cyclonedx.json --only-fixed --fail-on critical
Grype pulls vulnerability data from NVD, GitHub Security Advisories, Alpine SecDB, Red Hat, Debian, Ubuntu, Amazon Linux, and Oracle security databases, providing broader coverage than NVD alone.grype sbom:sbom-cyclonedx.json --only-fixed --fail-on critical
Grype从NVD、GitHub安全公告、Alpine SecDB、Red Hat、Debian、Ubuntu、Amazon Linux和Oracle安全数据库获取漏洞数据,提供比NVD更广泛的覆盖范围。Step 7: Generate Compliance Report
步骤7:生成合规报告
Produce a structured report suitable for regulatory compliance:
SBOM VULNERABILITY ANALYSIS REPORT
====================================
SBOM File: app-sbom-cyclonedx.json
Format: CycloneDX v1.5
Analysis Date: 2026-03-19
Total Components: 247
Total Dependencies: 1,842 (direct: 34, transitive: 213)
VULNERABILITY SUMMARY
Critical: 3 components / 5 CVEs
High: 11 components / 18 CVEs
Medium: 27 components / 41 CVEs
Low: 8 components / 12 CVEs
CRITICAL FINDINGS
1. lodash@4.17.20
CVE-2021-23337 (CVSS 7.2) - Command Injection via template
CVE-2020-28500 (CVSS 5.3) - ReDoS in trimEnd
Dependents: 14 components (high blast radius)
Fix: Upgrade to 4.17.21+
2. log4j-core@2.14.1
CVE-2021-44228 (CVSS 10.0) - Log4Shell RCE [CISA KEV]
CVE-2021-45046 (CVSS 9.0) - Incomplete fix bypass
Dependents: 8 components
Fix: Upgrade to 2.17.1+
DEPENDENCY GRAPH RISKS
Most depended-on: core-util@1.2.3 (47 dependents)
Deepest chain: app -> framework -> adapter -> codec -> zlib (5 levels)
Bottleneck components: 3 components on >50% of dependency paths
LICENSE COMPLIANCE
Copyleft licenses found: 2 (GPL-3.0 in libxml2, AGPL-3.0 in mongodb-driver)
Review required for commercial distribution生成符合监管要求的结构化报告:
SBOM漏洞分析报告
====================================
SBOM文件: app-sbom-cyclonedx.json
格式: CycloneDX v1.5
分析日期: 2026-03-19
组件总数: 247
依赖项总数:1,842(直接:34,传递性:213)
漏洞摘要
严重: 3个组件 / 5个CVE
高: 11个组件 / 18个CVE
中: 27个组件 / 41个CVE
低: 8个组件 / 12个CVE
严重漏洞发现
1. lodash@4.17.20
CVE-2021-23337(CVSS 7.2)- 模板注入命令执行
CVE-2020-28500(CVSS 5.3)- trimEnd中的正则表达式拒绝服务(ReDoS)
依赖者:14个组件(影响范围大)
修复方案:升级至4.17.21+
2. log4j-core@2.14.1
CVE-2021-44228(CVSS 10.0)- Log4Shell远程代码执行 [CISA KEV]
CVE-2021-45046(CVSS 9.0)- 不完整修复绕过
依赖者:8个组件
修复方案:升级至2.17.1+
依赖图风险
被依赖最多的组件:core-util@1.2.3(47个依赖者)
最深依赖链:app -> framework -> adapter -> codec -> zlib(5层)
瓶颈组件:3个组件位于超过50%的依赖路径上
许可证合规性
发现Copyleft许可证:2个(libxml2中的GPL-3.0,mongodb-driver中的AGPL-3.0)
商业分发需进行审查Key Concepts
核心概念
| Term | Definition |
|---|---|
| SBOM | Software Bill of Materials; a formal inventory of all components, libraries, and dependencies in a software product |
| CycloneDX | OWASP-maintained SBOM standard supporting JSON, XML, and protobuf formats with dependency graph and vulnerability data |
| SPDX | Linux Foundation SBOM standard focused on license compliance with support for package, file, and snippet-level detail |
| PURL | Package URL; a standardized scheme for identifying software packages across ecosystems (e.g., pkg:npm/lodash@4.17.21) |
| CPE | Common Platform Enumeration; NIST naming scheme for IT products used to correlate with NVD CVE data |
| NVD | National Vulnerability Database; US government repository of vulnerability data indexed by CVE identifiers |
| Transitive Dependency | A dependency not directly declared but pulled in through the dependency chain of direct dependencies |
| CISA KEV | CISA Known Exploited Vulnerabilities catalog; CVEs confirmed to be actively exploited in the wild |
| 术语 | 定义 |
|---|---|
| SBOM | 软件物料清单;软件产品中所有组件、库和依赖项的正式清单 |
| CycloneDX | OWASP维护的SBOM标准,支持JSON、XML和protobuf格式,包含依赖图和漏洞数据 |
| SPDX | Linux基金会的SBOM标准,专注于许可证合规,支持包、文件和代码片段级别的细节 |
| PURL | 包URL;跨生态系统识别软件包的标准化方案(例如:pkg:npm/lodash@4.17.21) |
| CPE | 通用平台枚举;NIST制定的IT产品命名方案,用于关联NVD CVE数据 |
| NVD | 国家漏洞数据库;美国政府维护的漏洞数据仓库,按CVE标识符索引 |
| Transitive Dependency | 传递性依赖;未直接声明但通过直接依赖的依赖链引入的依赖项 |
| CISA KEV | CISA已知被利用漏洞目录;已确认在野外被主动利用的CVE |
Tools & Systems
工具与系统
- syft (Anchore): Open-source SBOM generator supporting 30+ package ecosystems and CycloneDX/SPDX output
- grype (Anchore): Vulnerability scanner that accepts SBOMs as input and correlates against multiple advisory databases
- cyclonedx-python-lib: Python library for creating, parsing, and validating CycloneDX SBOMs programmatically
- lib4sbom: Python library for parsing both SPDX and CycloneDX format SBOMs
- nvdlib: Python wrapper for the NVD 2.0 API supporting CVE and CPE queries with rate limit management
- OWASP Dependency-Track: Platform for continuous SBOM analysis, vulnerability tracking, and policy enforcement
- syft(Anchore):开源SBOM生成工具,支持30+包生态系统和CycloneDX/SPDX输出
- grype(Anchore):漏洞扫描器,接受SBOM作为输入,关联多个咨询数据库
- cyclonedx-python-lib:用于以编程方式创建、解析和验证CycloneDX SBOM的Python库
- lib4sbom:用于解析SPDX和CycloneDX格式SBOM的Python库
- nvdlib:NVD 2.0 API的Python包装器,支持CVE和CPE查询及速率限制管理
- OWASP Dependency-Track:用于持续SBOM分析、漏洞跟踪和策略执行的平台
Common Scenarios
常见场景
Scenario: Assessing Vendor Software After Log4Shell Disclosure
场景:Log4Shell披露后评估供应商软件
Context: After the Log4Shell (CVE-2021-44228) disclosure, the security team needs to determine which vendor-supplied applications contain vulnerable versions of log4j. Several vendors have provided SBOMs per contractual requirements.
Approach:
- Collect all vendor SBOMs (CycloneDX or SPDX JSON format)
- Parse each SBOM and search for log4j-core components with versions < 2.17.1
- Query NVD API for the specific CVEs (CVE-2021-44228, CVE-2021-45046, CVE-2021-45105)
- Build dependency graphs to identify which application components depend on log4j
- Calculate blast radius: how many services and endpoints are exposed
- Generate prioritized remediation report sorted by exposure and business criticality
- Cross-validate findings with grype scan of the same SBOMs
Pitfalls:
- Vendor SBOMs may be incomplete, missing shaded/bundled JAR files that embed log4j
- SPDX and CycloneDX version differences may affect parser compatibility
- NVD API rate limits can slow analysis when scanning hundreds of components without an API key
- CPE names in SBOMs may not exactly match NVD entries, requiring fuzzy matching
- Transitive dependencies may include log4j even when it is not a direct dependency
背景:Log4Shell(CVE-2021-44228)披露后,安全团队需要确定哪些供应商提供的应用程序包含易受攻击的log4j版本。多家供应商已根据合同要求提供了SBOM。
方法:
- 收集所有供应商SBOM(CycloneDX或SPDX JSON格式)
- 解析每个SBOM并搜索版本 < 2.17.1的log4j-core组件
- 查询NVD API获取特定CVE(CVE-2021-44228、CVE-2021-45046、CVE-2021-45105)的信息
- 构建依赖图以识别哪些应用组件依赖log4j
- 计算影响范围:有多少服务和端点暴露风险
- 生成按暴露程度和业务优先级排序的修复报告
- 使用grype扫描相同SBOM交叉验证结果
常见陷阱:
- 供应商SBOM可能不完整,遗漏嵌入log4j的阴影/捆绑JAR文件
- SPDX和CycloneDX版本差异可能影响解析兼容性
- 无API密钥时,NVD API速率限制会减慢数百个组件的分析速度
- SBOM中的CPE名称可能与NVD条目不完全匹配,需要模糊匹配
- 即使不是直接依赖,传递性依赖也可能包含log4j