Supply Chain & Third-Party Risk
Modern systems depend on hundreds of third-party components — open-source libraries, SaaS integrations, cloud services, and outsourced development. A TRA is incomplete without assessing these dependencies. This section covers SBOM analysis, vendor tiering, OSS risk scoring, and Nth-party cascading risk.
Related Tools & Sections
Supply Chain Risk Landscape
Software Supply Chain Attack Surface
SBOM Analysis
A Software Bill of Materials (SBOM) is the foundation of supply chain risk assessment. Two major standards exist — use both for comprehensive coverage.
SPDX (Linux Foundation)
- • ISO/IEC 5962:2021 standard
- • Focus: license compliance + security
- • Formats: SPDX, JSON, RDF, YAML
- • Strong license expression support
- • Used by: Linux kernel, NTIA guidance
CycloneDX (OWASP)
- • OWASP flagship project
- • Focus: security + vulnerability tracking
- • Formats: XML, JSON, Protocol Buffers
- • Built-in VEX (Vulnerability Exploitability eXchange)
- • Used by: OWASP, DHS CISA, commercial tools
# SBOM Risk Analysis Script
# Analyzes CycloneDX SBOM for supply chain risk indicators
import json
from dataclasses import dataclass, field
from datetime import datetime, timezone
@dataclass
class DependencyRisk:
name: str
version: str
risk_score: float = 0.0
risk_factors: list = field(default_factory=list)
def analyze_sbom(sbom_path: str) -> list[DependencyRisk]:
"""Analyze SBOM for supply chain risk indicators."""
with open(sbom_path, "r") as f:
sbom = json.load(f)
findings = []
components = sbom.get("components", [])
for comp in components:
risk = DependencyRisk(
name=comp.get("name", "unknown"),
version=comp.get("version", "unknown"),
)
# Check for known vulnerabilities
vulns = comp.get("vulnerabilities", [])
if vulns:
critical = sum(
1 for v in vulns
if v.get("severity", "").lower() == "critical"
)
risk.risk_score += critical * 25 + len(vulns) * 5
risk.risk_factors.append(
f"{len(vulns)} known vulns ({critical} critical)"
)
# Check for outdated components
licenses = comp.get("licenses", [])
if not licenses:
risk.risk_score += 10
risk.risk_factors.append("No license declared")
else:
for lic in licenses:
license_id = lic.get("license", {}).get("id", "")
if license_id in ("AGPL-3.0", "GPL-3.0-only"):
risk.risk_score += 15
risk.risk_factors.append(
f"Copyleft license: {license_id}"
)
# Check supplier information
supplier = comp.get("supplier", {})
if not supplier:
risk.risk_score += 10
risk.risk_factors.append("No supplier information")
# Flag components without hashes
hashes = comp.get("hashes", [])
if not hashes:
risk.risk_score += 15
risk.risk_factors.append("No integrity hashes")
if risk.risk_factors:
findings.append(risk)
# Sort by risk score descending
findings.sort(key=lambda r: r.risk_score, reverse=True)
return findings
def generate_risk_report(findings: list[DependencyRisk]) -> str:
"""Generate supply chain risk summary report."""
lines = ["Supply Chain Risk Analysis Report"]
lines.append("=" * 40)
lines.append(
f"Analysis Date: "
f"{datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}"
)
lines.append(f"Components Analyzed: {len(findings)} with findings")
lines.append("")
high_risk = [f for f in findings if f.risk_score >= 50]
medium_risk = [f for f in findings if 20 <= f.risk_score < 50]
low_risk = [f for f in findings if f.risk_score < 20]
lines.append(f"HIGH RISK: {len(high_risk)} components")
lines.append(f"MEDIUM RISK: {len(medium_risk)} components")
lines.append(f"LOW RISK: {len(low_risk)} components")
for risk_level, items in [
("HIGH", high_risk),
("MEDIUM", medium_risk),
]:
if items:
lines.append(f"\n--- {risk_level} RISK ---")
for item in items[:10]:
lines.append(
f" {item.name}@{item.version} "
f"(score: {item.risk_score})"
)
for factor in item.risk_factors:
lines.append(f" - {factor}")
return "\n".join(lines)# SBOM Risk Analysis Script
# Analyzes CycloneDX SBOM for supply chain risk indicators
import json
from dataclasses import dataclass, field
from datetime import datetime, timezone
@dataclass
class DependencyRisk:
name: str
version: str
risk_score: float = 0.0
risk_factors: list = field(default_factory=list)
def analyze_sbom(sbom_path: str) -> list[DependencyRisk]:
"""Analyze SBOM for supply chain risk indicators."""
with open(sbom_path, "r") as f:
sbom = json.load(f)
findings = []
components = sbom.get("components", [])
for comp in components:
risk = DependencyRisk(
name=comp.get("name", "unknown"),
version=comp.get("version", "unknown"),
)
# Check for known vulnerabilities
vulns = comp.get("vulnerabilities", [])
if vulns:
critical = sum(
1 for v in vulns
if v.get("severity", "").lower() == "critical"
)
risk.risk_score += critical * 25 + len(vulns) * 5
risk.risk_factors.append(
f"{len(vulns)} known vulns ({critical} critical)"
)
# Check for outdated components
licenses = comp.get("licenses", [])
if not licenses:
risk.risk_score += 10
risk.risk_factors.append("No license declared")
else:
for lic in licenses:
license_id = lic.get("license", {}).get("id", "")
if license_id in ("AGPL-3.0", "GPL-3.0-only"):
risk.risk_score += 15
risk.risk_factors.append(
f"Copyleft license: {license_id}"
)
# Check supplier information
supplier = comp.get("supplier", {})
if not supplier:
risk.risk_score += 10
risk.risk_factors.append("No supplier information")
# Flag components without hashes
hashes = comp.get("hashes", [])
if not hashes:
risk.risk_score += 15
risk.risk_factors.append("No integrity hashes")
if risk.risk_factors:
findings.append(risk)
# Sort by risk score descending
findings.sort(key=lambda r: r.risk_score, reverse=True)
return findings
def generate_risk_report(findings: list[DependencyRisk]) -> str:
"""Generate supply chain risk summary report."""
lines = ["Supply Chain Risk Analysis Report"]
lines.append("=" * 40)
lines.append(
f"Analysis Date: "
f"{datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}"
)
lines.append(f"Components Analyzed: {len(findings)} with findings")
lines.append("")
high_risk = [f for f in findings if f.risk_score >= 50]
medium_risk = [f for f in findings if 20 <= f.risk_score < 50]
low_risk = [f for f in findings if f.risk_score < 20]
lines.append(f"HIGH RISK: {len(high_risk)} components")
lines.append(f"MEDIUM RISK: {len(medium_risk)} components")
lines.append(f"LOW RISK: {len(low_risk)} components")
for risk_level, items in [
("HIGH", high_risk),
("MEDIUM", medium_risk),
]:
if items:
lines.append(f"\n--- {risk_level} RISK ---")
for item in items[:10]:
lines.append(
f" {item.name}@{item.version} "
f"(score: {item.risk_score})"
)
for factor in item.risk_factors:
lines.append(f" - {factor}")
return "\n".join(lines)NIST SSDF (SP 800-218)
The Secure Software Development Framework defines practices that software producers should follow. Use SSDF as an assessment checklist when evaluating vendor security maturity.
| Practice Group | Focus | Key Assessment Questions |
|---|---|---|
| PO — Prepare the Organization | Security governance, roles, tooling | Does the vendor have a documented SDLC? Security team? Training program? |
| PS — Protect the Software | Code integrity, access controls, artifact security | Are builds reproducible? Artifacts signed? Source access controlled? |
| PW — Produce Well-Secured Software | Secure design, code review, testing | Threat modeling done? SAST/DAST in pipeline? Dependency scanning? |
| RV — Respond to Vulnerabilities | Vulnerability disclosure, patching, communication | SLAs for critical patches? Public disclosure policy? CVE assignment? |
Vendor Risk Tiering
Not all vendors require the same assessment depth. Tier vendors based on data access, integration depth, and business criticality to allocate assessment effort efficiently.
Tier 1 — Critical (Full Assessment)
Vendors with direct access to sensitive data or critical business processes.
- • Criteria: Processes PII/PHI/PCI data, has network access, single point of failure
- • Assessment: Full security questionnaire (SIG/CAIQ), SOC 2 Type II review, pentest results, on-site audit, SBOM review
- • Review frequency: Annual + triggered by incidents
- • Examples: Cloud infrastructure (AWS/Azure), payment processor, HRIS, EHR system
Tier 2 — High (Standard Assessment)
Vendors with limited data access or non-critical integrations.
- • Criteria: Internal data access, API integration, indirect customer impact
- • Assessment: Security questionnaire, SOC 2 report review, contract review
- • Review frequency: Annual
- • Examples: Project management SaaS, CI/CD platform, monitoring tools
Tier 3 — Standard (Light Assessment)
Vendors with no data access or minimal integration.
- • Criteria: No sensitive data, website-only tools, replaceable
- • Assessment: Self-attestation, public security page review, contract clauses
- • Review frequency: Biennial or on renewal
- • Examples: Marketing analytics, design tools, office supplies
OSS Criticality Scoring
Open-source dependencies require different risk assessment than commercial vendors. Evaluate them on health metrics rather than questionnaires.
| Risk Factor | Low Risk | Medium Risk | High Risk |
|---|---|---|---|
| Maintainer count | 5+ active maintainers | 2–4 maintainers | Single maintainer |
| Last commit | < 30 days | 30–180 days | > 180 days |
| Security policy | SECURITY.md + disclosure process | Issue-based reporting | No security policy |
| OpenSSF Scorecard | Score ≥ 7/10 | Score 4–6/10 | Score < 4/10 or N/A |
| Signed releases | GPG/Sigstore signed | Checksum only | No verification |
Nth-Party Cascading Risk
Your vendors also have vendors (4th parties), creating cascading dependency chains. A breach at a 4th party can propagate through your entire supply chain.
Nth-Party Risk Cascade
Concentration Risk
SaaS Risk Assessment
SaaS Vendor Risk Assessment Checklist
═════════════════════════════════════
DATA SECURITY
□ Where is data stored? (region, jurisdiction)
□ Encryption at rest (algorithm, key management)
□ Encryption in transit (TLS version, cipher suites)
□ Data isolation model (single-tenant vs multi-tenant)
□ Data retention and deletion policies
□ Right to audit clause in contract
ACCESS CONTROL
□ SSO/SAML/OIDC integration available?
□ SCIM provisioning supported?
□ IP allowlisting capability
□ Role-based access control granularity
□ MFA enforcement options
□ Session management controls
INCIDENT RESPONSE
□ Documented incident response plan?
□ Breach notification SLA (e.g., 72 hours for GDPR)
□ Customer communication process
□ Post-incident report provided?
□ Insurance coverage
COMPLIANCE & ASSURANCE
□ SOC 2 Type II report (current period)
□ ISO 27001 certification (current)
□ Penetration test results (redacted OK)
□ GDPR / CCPA compliance attestation
□ Industry-specific (PCI, HIPAA, FedRAMP)
EXIT STRATEGY
□ Data export format and mechanism
□ Data deletion confirmation upon termination
□ Transition assistance period
□ API data extraction capability
□ Contract termination notice periodSaaS Vendor Risk Assessment Checklist
═════════════════════════════════════
DATA SECURITY
□ Where is data stored? (region, jurisdiction)
□ Encryption at rest (algorithm, key management)
□ Encryption in transit (TLS version, cipher suites)
□ Data isolation model (single-tenant vs multi-tenant)
□ Data retention and deletion policies
□ Right to audit clause in contract
ACCESS CONTROL
□ SSO/SAML/OIDC integration available?
□ SCIM provisioning supported?
□ IP allowlisting capability
□ Role-based access control granularity
□ MFA enforcement options
□ Session management controls
INCIDENT RESPONSE
□ Documented incident response plan?
□ Breach notification SLA (e.g., 72 hours for GDPR)
□ Customer communication process
□ Post-incident report provided?
□ Insurance coverage
COMPLIANCE & ASSURANCE
□ SOC 2 Type II report (current period)
□ ISO 27001 certification (current)
□ Penetration test results (redacted OK)
□ GDPR / CCPA compliance attestation
□ Industry-specific (PCI, HIPAA, FedRAMP)
EXIT STRATEGY
□ Data export format and mechanism
□ Data deletion confirmation upon termination
□ Transition assistance period
□ API data extraction capability
□ Contract termination notice periodSection Summary
Key Takeaways
- • SBOMs (SPDX/CycloneDX) are foundational for dependency risk analysis
- • NIST SSDF provides a vendor security maturity assessment framework
- • Tier vendors by data access and criticality to allocate assessment effort
- • OSS dependencies need health metric evaluation, not questionnaires
- • Map Nth-party dependencies to identify concentration risk
Next Steps
- • Section 09: Cloud & AI Risk — cloud-native and AI/ML risk assessment
- • CI/CD & Supply Chain — pipeline attack patterns