SBOM Generation Review
Current State
SBOM Tool Used
- Tool:
anchore/sbom-actionv0.20.9 - Underlying Engine: Syft (by Anchore)
- Version Hash:
8e94d75ddd33f69f691467e42275782e4bfefe84
Format
- Primary Format: CycloneDX JSON (
cyclonedx-json) - File Name:
sbom.cdx.json - Standard Compliance: CycloneDX specification (industry-standard SBOM format)
Generation Trigger
SBOM generation occurs in two workflows:
-
Tag Assets Workflow (
.github/workflows/tag-assets.yml)- Triggered on: Git tags matching
v*.*.*pattern - Triggered on: Manual workflow dispatch
- Purpose: Generate SBOM for tagged releases
- Triggered on: Git tags matching
-
Release Workflow (
.github/workflows/release.yml)- Triggered on: Manual workflow dispatch only
- Purpose: Generate SBOM during npm package publication
Files Generated
sbom.cdx.json- CycloneDX JSON format SBOM- Uploaded as GitHub Actions artifact with name:
sbom.cdx.json
Attachment to Release
CRITICAL ISSUE IDENTIFIED: The SBOM is generated and uploaded as a GitHub Actions artifact, but it is NOT automatically attached to the GitHub Release.
Current Behavior:
- SBOM is generated by
anchore/sbom-action - SBOM is uploaded as workflow artifact (accessible from workflow run page)
- GitHub Release is created by
softprops/action-gh-release - Gap: No step to attach the SBOM artifact to the release
What's Working
-
Standardized SBOM Generation
- Uses industry-standard CycloneDX JSON format
- Leverages reputable Anchore/Syft tooling
- Pinned to specific version hash for reproducibility
-
Comprehensive Dependency Scanning
- Scans entire project directory (
.) - Captures all dependencies from
pnpm-lock.yaml - Includes transitive dependencies
- Scans entire project directory (
-
Dual Workflow Coverage
- SBOM generated for both tagged releases and npm publications
- Ensures SBOM availability across different release mechanisms
-
Security Documentation
- Excellent documentation in
docs/security-supply-chain.md - Clear verification procedures documented
- Integration with broader security strategy (OSV scanning, Harden-Runner)
- Excellent documentation in
-
Build Environment
- SBOM generated after successful build step
- Ensures accuracy of dependency resolution
- Uses frozen lockfile for deterministic builds
Issues Found
Critical (P0)
- SBOM Not Attached to GitHub Releases
- Problem: SBOM artifact exists but isn't included in release assets
- Impact: Users cannot access SBOM from release page; must dig into workflow run artifacts
- Evidence: No
files:parameter insoftprops/action-gh-releasestep - Expected Behavior: SBOM should be downloadable from Releases page alongside other assets
High (P1)
-
Missing Vulnerability Scanning of SBOM
- Problem: SBOM is generated but not scanned for vulnerabilities in tag-assets workflow
- Impact: Releases may include known vulnerabilities without immediate detection
- Note: Separate OSV scanning exists in
security.ymlbut runs on schedule, not on release
-
No SBOM Validation Step
- Problem: No verification that generated SBOM is valid CycloneDX
- Impact: Malformed SBOM could be published without detection
- Recommendation: Add validation step using CycloneDX CLI or similar
Medium (P2)
-
Single Format Only
- Problem: Only CycloneDX JSON format is generated
- Impact: Organizations requiring SPDX format cannot consume SBOM
- Note: Documentation mentions this as acceptable; SPDX addition if "downstream tooling demands"
-
No SBOM Signing/Attestation
- Problem: SBOM is not cryptographically signed
- Impact: No way to verify SBOM integrity or authenticity
- Note: NPM provenance exists for package, but not SBOM-specific attestation
Low (P3)
- Artifact Retention Not Explicitly Set
- Problem: Workflow artifacts may expire based on default retention
- Impact: SBOM artifacts could be lost after retention period
- Note: Less critical if attached to release (permanent storage)
Recommendations
Immediate Actions (P0)
- Attach SBOM to GitHub Releases
- name: Create GitHub Release
uses: softprops/action-gh-release@v2.4.2
with:
generate_release_notes: true
files: |
sbom.cdx.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Short-Term Actions (P1)
-
Add SBOM Vulnerability Scanning
- Add Grype or Trivy scan step after SBOM generation
- Gate release if critical vulnerabilities detected
- Example using Grype:
- name: Scan SBOM for Vulnerabilities
uses: anchore/scan-action@v3
with:
sbom: sbom.cdx.json
fail-build: true
severity-cutoff: high -
Add SBOM Validation
- name: Validate SBOM
run: |
npm install -g @cyclonedx/cyclonedx-cli
cyclonedx validate --input-file sbom.cdx.json --fail-on-errors
Medium-Term Actions (P2)
-
Consider Multi-Format SBOM Generation
- Evaluate if any consumers require SPDX format
- If yes, generate both CycloneDX and SPDX formats
- Use separate artifact names:
sbom.cdx.jsonandsbom.spdx.json
-
Implement SBOM Signing
- Use Cosign for keyless signing
- Generate attestation using GitHub OIDC
- Example (for container images):
# Add at job level
permissions:
id-token: write # Required for OIDC token
attestations: write # Required for attestation creation
steps:
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Create SBOM Attestation
run: |
# For container images: replace with your image and digest
cosign attest --type cyclonedx \
--predicate sbom.cdx.json \
${{ env.IMAGE_NAME }}@sha256:${{ env.IMAGE_DIGEST }}Note: For npm packages (non-container), consider using npm provenance (
--provenanceflag) or the GitHub Attestations API instead of Cosign, as Cosign is primarily designed for container images.
Long-Term Actions (P3)
-
Set Explicit Artifact Retention
- name: Generate SBOM
uses: anchore/sbom-action@8e94d75ddd33f69f691467e42275782e4bfefe84
with:
path: .
format: cyclonedx-json
artifact-name: sbom.cdx.json
retention-days: 90 -
Add VEX Support
- Implement CycloneDX VEX extension
- Document known vulnerabilities with exploitability context
- Reduces false positive noise in vulnerability scanners
Best Practices Compliance
- SBOM generated for every release
- Uses standard format (CycloneDX)
- Attached to GitHub releases (CRITICAL GAP)
- Includes all dependencies
- Machine-readable format
- Vulnerability scanning performed at release time (scheduled only)
- SBOM is signed/attested
Compliance Score: 4/7 (57%)
Security Integration Analysis
Current Security Stack
The project has a robust security posture with:
- NPM Provenance - Sigstore-backed attestation for published packages
- Dependency Review - Gates PRs with vulnerable dependencies (moderate+ severity)
- OSV Scheduled Scanning - Weekly vulnerability detection
- Harden-Runner - Egress monitoring in audit mode
- SBOM Generation - CycloneDX inventory (this review's focus)
Integration Gaps
-
SBOM and OSV Scanning Are Disconnected
- OSV runs weekly on schedule
- SBOM generated on release
- No immediate vulnerability check when releasing
-
SBOM Accessibility
- Documented as "download from workflow artifacts"
- Should be first-class release asset for transparency
-
Provenance vs SBOM Attestation
- NPM package has provenance
- SBOM itself has no attestation
- Both should be verifiable
Next Steps
Phase 1: Fix Critical Gap (Week 1)
- Update
tag-assets.ymlto attach SBOM to release - Test with pre-release tag (e.g.,
v0.0.0-sbom-test) - Verify SBOM appears in release assets
- Update
release.ymlwith same change for consistency
Phase 2: Add Quality Gates (Week 2-3)
- Add SBOM validation step
- Implement vulnerability scanning of SBOM at release time
- Document new quality gates in
security-supply-chain.md
Phase 3: Enhanced Security (Week 4+)
- Evaluate SBOM signing with Cosign
- Consider SPDX format if needed
- Explore VEX integration for vulnerability context
Verification Steps
After Phase 1 implementation:
- Create test tag:
git tag v0.0.1-sbom-fix && git push --tags - Monitor workflow run
- Navigate to Releases page
- Confirm
sbom.cdx.jsonappears in release assets - Download and validate with:
cyclonedx validate --input-file sbom.cdx.json --fail-on-errors
Comparison with Industry Standards
CISA Minimum Elements for SBOM (2021)
- Supplier Name
- Component Name
- Version of Component
- Other Unique Identifiers
- Dependency Relationship
- SBOM Author
- Timestamp
All minimum elements present in CycloneDX format.
NTIA Framing Document Compliance
- Automation support (machine-readable JSON)
- Standardized format (CycloneDX)
- Practices and processes documented
- Access and delivery (partially - not on release page)
- Unique identification (package URIs)
Cost-Benefit Analysis
Current State Costs
- Developer Time: Minimal (automated)
- CI Minutes: ~30 seconds per release
- Storage: ~50KB per SBOM artifact
Gap Remediation Costs
- Phase 1 (Attach to Release): 1-2 hours (one-time)
- Phase 2 (Validation + Scanning): 4-6 hours (one-time)
- Phase 3 (Signing): 8-10 hours (one-time)
Benefits
- Transparency: Users can audit dependencies
- Security: Faster vulnerability remediation with accurate inventory
- Compliance: Meets government/enterprise SBOM requirements
- Trust: Demonstrates supply chain maturity
Conclusion
The project has a strong foundation for SBOM generation using industry-standard tools and formats. However, there is a critical gap preventing the SBOM from being useful to end users: it's not attached to GitHub releases.
Summary
- Status: SBOM generation is configured correctly but incomplete
- Priority: HIGH - Fix attachment to releases immediately
- Effort: LOW - Simple workflow modification
- Impact: HIGH - Enables SBOM consumption by users and tooling
Recommendation
Proceed with Phase 1 immediately. The fix is simple, low-risk, and high-value. Once releases include SBOM assets, the project will meet industry best practices for software transparency.