Automated CRA Compliance for Embedded Linux
Generate spec-compliant OpenVEX reports from Yocto builds by filtering CVEs against your actual hardware configuration.
Getting Started · Features · CLI Reference · Integration · Architecture
The EU Cyber Resilience Act (CRA) mandates vulnerability disclosure for connected devices. If you build embedded Linux products with Yocto, you face a critical challenge:
Your SBOM lists 200+ packages. A scanner flags 500 CVEs. How many actually affect your device?
Most are false positives:
| False Positive Source | Why It Doesn't Apply |
|---|---|
gcc-native, cmake-native |
Host-only build tools, never deployed on target |
CONFIG_BT drivers |
Kernel compiled without Bluetooth support |
| WiFi chipset firmware | status = "disabled" in your Device Tree |
Manual triage of hundreds of CVEs per build is unsustainable. BitVex automates it.
BitVex takes inputs from your Yocto build and produces an auditable VEX document:
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ SBOM │ │ Kernel │ │ Device │
│ (SPDX) │ │ .config │ │ Tree │
└──────┬──────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
└───────────────────┼────────────────────┘
│
┌──────▼──────┐
│ BitVex │
└──────┬──────┘
│
┌──────▼──────┐
│ OpenVEX / │
│ SARIF │
└─────────────┘
Result: A machine-readable document that tells scanners exactly which CVEs are real, which are mitigated by your hardware config, and why.
| Filter | Input | Rule | OpenVEX Justification |
|---|---|---|---|
| Native Recipes | SBOM package names | Packages ending in -native are build host tools |
component_not_present |
| Kernel Config | .config file |
Drivers with CONFIG_XXX not set to =y or =m |
vulnerable_code_not_present |
| Device Tree | .dts / .dtb |
Peripherals with status = "disabled" |
vulnerable_code_not_in_execute_path |
| U-Boot Config | U-Boot .config |
Bootloader drivers not compiled | vulnerable_code_not_present |
BitVex integrates FIRST.org's Exploit Prediction Scoring System to prioritize CVEs by real-world exploitability:
| CVE | Package | EPSS | Percentile | Status |
|--------------|-------------|-------|------------|----------|
| CVE-2021-3749| axios@0.21.0| 8.9% | 92.7% | affected |
| CVE-2021-23337| lodash@4.17| 4.3% | 89.1% | affected |
| CVE-2020-8203 | lodash@4.17| 2.5% | 85.7% | affected |
- Online mode: queries EPSS API in real-time
- Offline mode: download CSV database for air-gapped environments
- CI gating:
--fail-on-high/--fail-on-criticalexit codes - Alias resolution: GHSA/OSV vulnerability IDs are automatically mapped to CVE-xxxx via OSV API for EPSS lookup
Define custom filtering rules in bitvex.toml:
[author]
name = "Mi Empresa <security@empresa.com>"
[[rules]]
name = "OpenSSL parcheado"
cve = "CVE-2024-12345"
package = "openssl"
status = "not_affected"
justification = "vulnerable_code_not_present"
impact_statement = "Parcheado manualmente en nuestra build"
[[rules]]
name = "WiFi deshabilitado"
cve_pattern = "CVE-2024-*"
package = "linux-firmware"
status = "not_affected"
justification = "component_not_present"Download vulnerability databases and scan without internet — perfect for air-gapped environments:
# Download OSV database (~35 MB for Linux + Alpine + crates.io)
bitvex download-db --profile medium
# Download EPSS database (~250 MB)
bitvex download-epss-db
# Scan offline (no internet needed)
bitvex --offline --epss-offline --sbom ... --kernel-config ... --device-tree ...Compare two builds and see what changed:
bitvex diff --old v1.spdx.json --new v2.spdx.json╔══════════════════════════════════════════════════════╗
║ BitVex - SBOM Diff Report ║
╠══════════════════════════════════════════════════════╣
║ Packages added: 5 ║
║ Packages removed: 2 ║
║ Packages updated: 12 ║
╚══════════════════════════════════════════════════════╝
Compare two VEX documents to track changes over time:
bitvex delta --old report-v1.vex.json --new report-v2.vex.json╔══════════════════════════════════════════════════════╗
║ BitVex - VEX Delta Report ║
╠══════════════════════════════════════════════════════╣
║ New CVEs: 3 ║
║ Resolved CVEs: 1 ║
║ Status changes: 2 ║
╚══════════════════════════════════════════════════════╝
Export to OpenVEX (default) or SARIF for GitHub Security tab:
# OpenVEX (default)
bitvex --sbom ... --output report.vex.json
# SARIF for GitHub Security
bitvex --sbom ... --format sarif --output report.sarif.jsonChoose your database size based on your needs:
| Profile | Ecosystems | Size | Use case |
|---|---|---|---|
small |
Linux | ~29 MB | Kernel-only devices |
medium |
Linux, Alpine, crates.io | ~35 MB | Typical embedded |
big |
+ Debian, PyPI | ~116 MB | Full coverage |
complete |
All 10 ecosystems | ~822 MB | Maximum audit |
Exit codes for pipeline gating:
# Fail if any CVE is not mitigated
bitvex --sbom ... --fail-on-any
# Fail if any CVE has EPSS > 0.7 (high exploitability)
bitvex --sbom ... --epss --fail-on-high
# Fail if any CVE has EPSS > 0.9 (critical)
bitvex --sbom ... --epss --fail-on-criticalBitVex automatically detects compiled Device Tree binaries and decompiles them:
# Works with both .dts and .dtb
bitvex --sbom ... --device-tree board.dtbBitVex can continuously monitor your builds for new vulnerabilities. It watches SBOMs, kernel configs, and device trees for changes, automatically re-scans, and tracks CVE lifecycle in a local SQLite database.
# Start watching (monitors files for changes)
bitvex watch --config bitvex-watch.toml
# Check status of monitored projects
bitvex status
# View details for a specific project
bitvex status --project "iMX8MP EVK"debounce_secs = 5
output_dir = "./bitvex-reports"
[[projects]]
name = "iMX8MP EVK"
sbom = "build/imx8mp.spdx.json"
rules = "bitvex.toml"
author = "Mi Empresa <security@empresa.com>"
[[projects.configs]]
type = "kernel"
path = "build/.config"
[[projects.configs]]
type = "uboot"
path = "build/u-boot/.config"
[[projects.device_trees]]
path = "build/board.dts"
# Multiple projects supported
[[projects]]
name = "Raspberry Pi 4"
sbom = "build/rpi4.spdx.json"
[[projects.configs]]
type = "kernel"
path = "build/rpi4-.config"
[[projects.device_trees]]
path = "build/bcm2711.dts"How it works:
- Initial scan of all projects on startup
- Watches files using inotify (Linux) — near-zero CPU when idle
- Debounced re-scan (5s default) when files change
- Compares with previous scan in SQLite to detect new CVEs
- Saves reports to
output_dirwith timestamps bitvex statusshows last scan results for all projects
Status output:
╔══════════════════════════════════════════════════════════╗
║ BitVex - Project Status ║
╠══════════════════════════════════════════════════════════╣
║ Monitored projects: 2 ║
╚══════════════════════════════════════════════════════════╝
+------------------+---------------------+----------+---------+
| Project | Last Scan | Affected | Status |
+------------------+---------------------+----------+---------+
| iMX8MP EVK | 2024-06-30T10:30:00 | 4 | ⚠ warn |
| Raspberry Pi 4 | 2024-06-30T10:35:00 | 0 | ✓ clean |
+------------------+---------------------+----------+---------+
- Rust 1.85+ (install via rustup)
- Files from your Yocto build:
- Required: SBOM in SPDX JSON format
- Optional: Kernel
.config, Device Tree (.dts/.dtb), U-Boot.config
git clone https://github.com/LManuXx/BitVex.git
cd BitVex
cargo install --path .# 1. Download vulnerability database (one time, ~35 MB)
bitvex download-db --profile medium
# 2. Scan your build
bitvex \
--sbom build/tmp/deploy/images/rpi4/image-spdx.json \
--kernel-config build/tmp/work/rpi4-linux/linux-raspberrypi/6.1/.config \
--device-tree build/tmp/work/rpi4-linux/linux-raspberrypi/6.1/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts \
--output rpi4-cra-report.vex.json \
--author "Acme Devices <security@acme.com>"
# 3. With EPSS scoring
bitvex \
--sbom build/image-spdx.json \
--epss \
--output report.vex.json
# 4. Scan offline (no internet needed)
bitvex \
--offline \
--sbom build/image-spdx.json \
--kernel-config build/.config \
--device-tree build/board.dts \
--rules bitvex.toml
# 5. All inputs optional (scan SBOM only)
bitvex --sbom build/image-spdx.json --epss --output report.vex.json╔══════════════════════════════════════════════════════╗
║ BitVex - CRA Compliance Report ║
╠══════════════════════════════════════════════════════╣
║ Total packages analyzed: 142 ║
║ Native packages filtered: 23 ║
║ Kernel/U-Boot filtered: 12 ║
║ DTS disabled filtered: 5 ║
║ ───────────────────────────────────── ║
║ CVEs marked not_affected: 40 ║
║ CVEs marked fixed: 0 ║
║ Real CVEs to address: 12 ║
║ ───────────────────────────────────── ║
║ EPSS high risk (>0.7): 2 ║
║ EPSS critical (>0.9): 0 ║
╚══════════════════════════════════════════════════════╝
bitvex [OPTIONS] --sbom <PATH>
Options:
--sbom <PATH> SBOM in SPDX JSON format (required)
--kernel-config <PATH> Linux kernel .config (optional, multiple)
--uboot-config <PATH> U-Boot .config (optional)
--device-tree <PATH> Device Tree .dts/.dtb (optional)
-o, --output <PATH> Output file [default: bitvex-report.vex.json]
--format <FORMAT> Output format: openvex | sarif
--author <STRING> VEX document author
--rules <PATH> bitvex.toml rules file
--offline Use offline OSV database
--download-db Download DB before scanning
--profile <PROFILE> Download profile (small/medium/big/complete)
--epss Enable EPSS scoring
--epss-offline Use offline EPSS database
--download-epss-db Download EPSS database
--epss-threshold <FLOAT> EPSS low_priority threshold [default: 0.0]
--fail-on-any Exit 1 if any CVE affected
--fail-on-high Exit 1 if EPSS > 0.7
--fail-on-critical Exit 1 if EPSS > 0.9
-y, --yes Skip confirmation prompts
-v, --verbose Debug logging
bitvex diff --old <PATH> --new <PATH> [--output <PATH>]bitvex delta --old <PATH> --new <PATH> [--output <PATH>]bitvex download-db [--profile <PROFILE>] [--ecosystems <LIST>] [-y]
bitvex download-epss-db [--db-path <PATH>] [-y]bitvex watch --config <PATH>Options:
-c, --config <PATH> Path to bitvex-watch.toml [default: bitvex-watch.toml]
bitvex status [--project <NAME>] [--db-path <PATH>]- name: Download OSV Database
run: bitvex download-db --profile medium -y
- name: Generate VEX Report
run: |
bitvex \
--offline \
--sbom build/image-spdx.json \
--kernel-config build/.config \
--device-tree build/board.dts \
--format sarif \
--output results.sarif.json \
--author "${{ github.repository_owner }} <ci@${{ github.repository_owner }}.com>"
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif.json
- name: Upload VEX Artifact
uses: actions/upload-artifact@v4
with:
name: vex-report
path: results.sarif.jsonAdd BitVex to your Yocto build as a post-build step in local.conf:
# Generate VEX report after image build
IMAGE_POSTPROCESS_COMMAND += "generate_vex_report; "
generate_vex_report() {
bitvex \
--offline \
--sbom ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.spdx.json \
--kernel-config ${STAGING_KERNEL_BUILDDIR}/.config \
--device-tree ${STAGING_KERNEL_BUILDDIR}/arch/${ARCH}/boot/dts/*.dts \
--output ${DEPLOY_DIR_IMAGE}/${IMAGE_NAME}.vex.json
}SBOM (SPDX 2.2 / 2.3 / 3.0 JSON)
Produced by Yocto's meta-spdxscanner or tools like syft. BitVex auto-detects the SPDX version.
SPDX 2.2/2.3:
name— package identifierversionInfo— version stringexternalRefs— optionalpurl(Package URL)
SPDX 3.0:
element[]withtype: "Package"packageVersion— version stringexternalIdentifier[]withtype: "purl"
Kernel .config
Standard Linux kernel configuration. Located at ${STAGING_KERNEL_BUILDDIR}/.config in a Yocto build. Supports multiple config fragments via --kernel-config.
Device Tree (.dts / .dtb)
Source format (.dts) or compiled binary (.dtb). BitVex auto-detects DTB and decompiles using dtc. Supports modern DTS syntax including /omit-if-no-ref/ blocks. To manually decompile:
dtc -I dtb -O dts -o board.dts board.dtbIn Yocto, the preprocessed DTS is typically in ${STAGING_KERNEL_BUILDDIR}/arch/${ARCH}/boot/dts/.
U-Boot .config
Same format as kernel .config. Located in the U-Boot build directory.
src/
├── main.rs CLI dispatch
├── lib.rs Public API exports
├── pipeline.rs Scan pipeline orchestration
├── cli.rs CLI args + subcommands (clap)
├── sbom/
│ ├── spdx.rs SPDX JSON parser (v2.2/v2.3)
│ └── diff.rs SBOM diff engine
├── osv/
│ ├── client.rs Async OSV API client (concurrent alias fetching)
│ ├── offline.rs Offline OSV provider
│ └── db.rs DB download with profiles + progress
├── epss/
│ ├── client.rs EPSS API client (online)
│ └── offline.rs EPSS CSV parser (offline)
├── filters/
│ ├── native.rs Host-only recipe filter
│ ├── kernel_config.rs .config cross-reference (known mappings + heuristics)
│ ├── device_tree.rs DTS/DTB status cross-reference
│ └── rules.rs Custom rules engine
├── rules/
│ └── mod.rs bitvex.toml parser + rule matching
├── vex/
│ ├── openvex.rs OpenVEX v0.2.0 generator
│ └── delta.rs VEX delta comparison
├── output/
│ ├── console.rs Console summary formatter (with progress bars)
│ └── sarif.rs SARIF 2.1.0 generator
└── watch/
├── mod.rs Watch module re-exports
├── config.rs bitvex-watch.toml parser
├── state.rs SQLite state management (CVE lifecycle tracking)
├── scanner.rs Scan execution wrapper for watch mode
└── watcher.rs File watcher with inotify + debouncing
cargo build # Compile
cargo test # Run 91 tests (70 unit + 16 integration + 5 doctest)
cargo clippy # Lint (0 warnings)
cargo fmt # FormatBitVex follows the principle of least privilege:
- No credentials required — OSV and EPSS APIs are free and anonymous
- Minimal data sent — only package names/versions transmitted to OSV/EPSS
- Offline mode — download DBs once, scan without internet
- Local processing — all filtering happens on your machine
- Deterministic output — same inputs produce the same VEX document
This project is licensed under the Server Side Public License (SSPL-1.0).
What this means:
- You can use, modify, and distribute BitVex freely for internal/non-commercial purposes
- If you offer BitVex as a service (SaaS), you must make your entire service stack open source under SSPL-1.0
- For commercial licensing or OEM integration, contact the author
Author: Manuel Neto Romero
- OpenVEX — VEX specification
- OSV — vulnerability database
- EPSS — exploit prediction scoring
- CISA — VEX minimum requirements
- Yocto Project — embedded Linux build system