VEX Decisions and Compliance ExportΒΆ

A Vulnerability Exploitability eXchange (VEX) document communicates precisely how each CVE affects a specific product in machine-readable format. VEX is required by emerging regulations including the EU Cyber Resilience Act (CRA), NIST SSDF guidance, and various industrial control system standards (IEC 62443).

The key insight of VEX is that vulnerability databases publish CVEs in the context of raw software components, not finished products. A CVE that is disabled by build configuration, protected by compiler hardening, or bounded by architectural isolation is not exploitable in your deployment. Without VEX, a downstream consumer of your SBOM has no way to make this distinction automatically.

For all BCA reference designs targeting Yocto 5 (Scarthgap) or Yocto 6+, decisions are recorded using the sbom-cve-review tool, then exported back into your recipes as CVE_STATUS metadata that becomes part of future SBOM reports. Both Yocto versions are fully supported thanks to the sbom-cve-check integration already present in the BCA reference design.

Note

Recommendation: Use sbom-cve-review to record CVE decisions with full audit trails, justifications, and VEX export capability. See the project for tool documentation.

Understanding VEX DecisionsΒΆ

Every VEX decision is a tuple of three elements:

decision = product + vulnerability + impact_status + justification
CVE Identifier

The CVE ID (e.g., CVE-2023-4911)

Affected Package

The package name from the SBOM (e.g., glibc)

Impact Status

One of five standardised values (see below)

Justification

A machine-readable reason code explaining why the CVE does or does not affect your product

Impact StatusesΒΆ

In Triage (default)

Analysis is underway. The CVE has been identified but not yet fully assessed. Use this as the initial state for new CVEs while you gather information.

Resolved

The vulnerability has been remediated by applying a patch or upgrading to a fixed version. No further action required.

False Positive

The CVE appeared in the scan but does not actually apply to this product. This typically occurs because the vulnerability scanner matched a package name without verifying that the affected code is present.

Not Affected

The CVE is definitively not exploitable in this product under its default configuration. Must include a justification from the standardised list below.

Exploitable

The CVE is confirmed exploitable in this product. Requires immediate remediation (patch or package upgrade).

Justifications for Not Affected StatusΒΆ

When assigning Not Affected status, you must provide a justification from the standardised list:

Code Not Present

The vulnerable code is not compiled into the binary. Applied to kernel CVEs disabled by Kconfig, or library functions not included.

Code Not Reachable

The vulnerable code exists but is never executed at runtime. Applied to library functions included in a package but not called by any running component.

Requires Configuration

Exploitability depends on a runtime configuration option not enabled in the default image. Example: an SSH CVE that only applies with password authentication enabled (Bunker uses key-only authentication).

Requires Dependency

Exploitability requires a package or feature not installed in the image.

Protected by Compiler

Compiler hardening options render the vulnerability unexploitable. Examples: stack-protector, FORTIFY_SOURCE, Control Flow Integrity (CFI), Position Independent Executables (PIE).

Protected at Runtime

A runtime mechanism prevents exploitation. In BCA, the hypervisor isolation boundary is a strong protection: Open World CVEs allowing privilege escalation are bounded by the hypervisor and cannot affect Bunker OS.

Protected by Mitigating Control

A system-level control substantially reduces risk. Requires documentation of the specific control and assessment of residual risk.

Recording CVE Decisions with sbom-cve-reviewΒΆ

The sbom-cve-review tool provides both GUI and CLI interfaces for reviewing CVEs and recording decisions.

Installation:

pip install sbom-cve-review

Quick Start - Serve Reports in GUI:

sbom-cve-review serve \
    --report bunker-os-image.sbom-cve-check.yocto.json \
    --workspace bunker-os-cve-decisions.json

# Open http://127.0.0.1:8000 in your browser

The GUI displays all packages and their CVEs, allows you to mark decisions, record justifications, and review them before export.

CLI Decision Management:

# List all current decisions
sbom-cve-review decision list \
    --workspace bunker-os-cve-decisions.json

# Add a decision for a specific CVE
sbom-cve-review decision add \
    --workspace bunker-os-cve-decisions.json \
    --cve CVE-2023-4911 \
    --package glibc \
    --reason not-applicable-config \
    --justification "Feature requiring this code is disabled in build"

# Export as JSON (for reporting)
sbom-cve-review decision list \
    --workspace bunker-os-cve-decisions.json \
    --json > cve-decisions-export.json

# Edit an existing decision (use 8-char ID prefix from list output)
sbom-cve-review decision edit a1b2c3d4 \
    --workspace bunker-os-cve-decisions.json \
    --reason disputed \
    --justification "Upstream disputes this CVE"

# Remove a decision
sbom-cve-review decision remove a1b2c3d4 \
    --workspace bunker-os-cve-decisions.json

Workflow for Bunker OS and Open WorldΒΆ

Process decisions independently for each image:

# Process Bunker OS SBOMs
sbom-cve-review serve \
    --report bunker-os-image.sbom-cve-check.yocto.json \
    --workspace bunker-os-cve-decisions.json \
    --port 8000

# In another terminal, process Open World SBOMs
sbom-cve-review serve \
    --report open-world-image.sbom-cve-check.yocto.json \
    --workspace open-world-cve-decisions.json \
    --port 8001

Record decisions for each image in its own workspace file. This maintains clear separation and allows different review/approval workflows if needed.

Exporting CVE Decisions to RecipesΒΆ

Once decisions are recorded, export them as BitBake metadata (CVE_STATUS entries) that will be embedded in future SBOM reports and provide long-term traceability.

Export CVE_STATUS lines:

sbom-cve-review export-bitbake \
    --workspace bunker-os-cve-decisions.json \
    --format bbappend \
    --output recipes-core/glibc/glibc_%.bbappend

This generates .bbappend files with CVE_STATUS declarations:

# recipes-core/glibc/glibc_%.bbappend
CVE_STATUS = "CVE-2023-4911:resolved \
              CVE-2023-6246:not-affected-config \
              CVE-2020-1234:disputed"

Apply the exports to your recipes:

# Review generated files
git diff

# Commit and rebuild
git add recipes-*/*.bbappend
git commit -m "CVE decisions: [date] review complete"
bitbake bunker-os-image

On the next build, the SBOM report will reflect these decisions, marking matching CVEs as resolved, ignored (not-affected), or noting the reasoning.

Audit Trail and Workspace PersistenceΒΆ

Decisions are persisted to JSON files (e.g., bunker-os-cve-decisions.json) for long-term record-keeping:

{
  "format": "yocto-cve-review-workspace",
  "version": "1",
  "created_at": "2026-05-21T10:00:00",
  "updated_at": "2026-05-21T10:30:00",
  "source_reports": [
    { "path": "bunker-os-image.sbom-cve-check.yocto.json", "image_name": "bunker-os-image" }
  ],
  "decisions": [
    {
      "decision_id": "a1b2c3d4e5f6a7b8",
      "cve_id": "CVE-2023-4911",
      "package_name": "glibc",
      "scope": "recipe",
      "reason": "not-applicable-config",
      "justification": "tunables feature disabled in configuration",
      "created_at": "2026-05-21T10:01:00",
      "updated_at": "2026-05-21T10:01:00"
    }
  ]
}

Store these workspace files in version control:

git add bunker-os-cve-decisions.json open-world-cve-decisions.json
git commit -m "CVE decisions: [date] [review team]"

This creates a permanent audit trail that regulators can review: when decisions were made, who made them, and what justifications were recorded.

Compliance Reporting and CRA/IEC 62443ΒΆ

For regulatory compliance (CRA, IEC 62443, FDA), archive the following artefacts for each product release:

  1. SBOM Reports (with CVE findings): - bunker-os-image.sbom-cve-check.yocto.json - open-world-image.sbom-cve-check.yocto.json

  2. CVE Decision Workspaces (audit trail): - bunker-os-cve-decisions.json - open-world-cve-decisions.json

  3. Exported Metadata (proof of implementation): - recipes-core/*/*.bbappend files with CVE_STATUS declarations

  4. Release Manifest: - Build date, Yocto version, meta-layers used - Summary of patches applied - Summary of CVEs triaged and decisions recorded

Example release structure:

releases/v1.0.0/
β”œβ”€β”€ MANIFEST.md                                      # Release metadata
β”œβ”€β”€ bunker-os-image.sbom-cve-check.yocto.json       # SBOM
β”œβ”€β”€ open-world-image.sbom-cve-check.yocto.json      # SBOM
β”œβ”€β”€ bunker-os-cve-decisions.json                    # CVE decision audit trail
β”œβ”€β”€ open-world-cve-decisions.json                   # CVE decision audit trail
β”œβ”€β”€ CVE_STATUS_exports/                              # Proof of implementation
β”‚   β”œβ”€β”€ glibc_%.bbappend
β”‚   β”œβ”€β”€ openssl_%.bbappend
β”‚   └── ... (one per affected recipe)
└── signed_approval.pdf                              # Security team sign-off

Example MANIFEST.md:

# Product Release v1.0.0

**Release Date**: 2026-05-21
**Build Date**: 2026-05-21T10:30:00Z
**Yocto Version**: 6.0 (Wrynose)
**Machine**: qemuarm64

## Meta-Layers
- poky: commit abc123def456
- meta-openembedded: commit def456ghi789
- meta-bsp-custom: commit ghi789jkl012

## Security Summary

| Image | Patched | Unpatched | Ignored | Notes |
|-------|---------|-----------|---------|-------|
| Bunker OS | 45 | 2 | 3 | 2 unpatched require review |
| Open World | 120 | 15 | 8 | 15 unpatched: 10 Not Affected (config), 5 Protected (hypervisor) |

## Unpatched CVEs Summary

### Bunker OS
- CVE-2023-6246 (glibc): Requires investigation
- CVE-2025-1111 (openssl): Pending upstream patch

### Open World
- CVEs 2023-1000 through 2025-0015: All marked Not Affected (see cve-decisions.json)

## Approval

- Security Team: [Name] on 2026-05-21
- Product Manager: [Name] on 2026-05-21

Continuous Integration for CVE ComplianceΒΆ

Integrate CVE decision reviews into your CI/CD pipeline:

# .gitlab-ci.yml
cve-review:
  stage: security
  script:
    - source oe-init-build-env build
    - bitbake bunker-os-image open-world-image
    - sbom-cve-review serve --report tmp/deploy/images/*/\*.sbom-cve-check.yocto.json \
        --workspace cve-decisions.json &
    - echo "Open http://your-ci-runner:8000 for CVE review"
    - # Manually review and record decisions, or use CI automation
    - sbom-cve-review export-bitbake --workspace cve-decisions.json --format bbappend
  artifacts:
    paths:
      - tmp/deploy/images/*/\*.sbom-cve-check.yocto.json
      - cve-decisions.json
      - recipes-*/*.bbappend
    expire_in: 1 year

Next StepsΒΆ

Once CVE decisions are recorded and exported, verify the SBOM generation pipeline by rebuilding and confirming the decisions are reflected in the new SBOM report (see SBOM Generation and CVE Analysis). Then proceed to final compliance documentation and release packaging.