Vex Csaf Embedded Not Affected Scale
title: "VEX and CSAF for Embedded Devices: Publishing "Not Affected" at Scale" description: "How to produce and distribute VEX documents and CSAF advisories for embedded firmware, enabling downstream consumers to filter false positives from vulnerability scans." date: 2026-04-15T20:03:00Z lastmod: 2026-04-15T20:03:00Z draft: false hero: "/images/hero/vex-csaf-embedded-not-affected-scale-1600x900.jpg" tags:

title: "VEX and CSAF for Embedded Devices: Publishing "Not Affected" at Scale" description: "How to produce and distribute VEX documents and CSAF advisories for embedded firmware, enabling downstream consumers to filter false positives from vulnerability scans." date: 2026-04-15T20:03:00Z lastmod: 2026-04-15T20:03:00Z draft: false hero: "/images/hero/vex-csaf-embedded-not-affected-scale-1600x900.jpg" tags:
- Embedded Linux
- ProteanOS
- Security category: dev
Every embedded firmware image contains hundreds of open-source packages. When a CVE is published against one of those packages, the immediate question is: "Are we actually affected?" For most CVEs, the answer is no - the vulnerable code path is not compiled in, the affected feature is disabled, or the exploitable interface is not exposed. VEX (Vulnerability Exploitability eXchange) and CSAF (Common Security Advisory Framework) provide standardized ways to communicate these "not affected" statements at scale.
The false positive problem
A typical embedded Linux image contains 200-500 packages. Over a year, 50-200 new CVEs will reference at least one of those packages. A naive scanner reports all of them, generating a list that is 80-90% false positives.
Without VEX, human engineers must triage each CVE individually:
- Identify which package version is in the image
- Read the CVE description and affected versions
- Determine if the vulnerable code path is compiled in
- Determine if the exploitable interface is exposed
- Document the analysis
- Repeat for every image variant
This does not scale. A product family with five image variants and 100 CVEs per year means 500 triage decisions, each taking 15-60 minutes.
What VEX provides
VEX is a structured format for communicating the exploitability status of a vulnerability in a specific product. Each VEX statement ties together a CVE identifier, the affected product (your firmware image or specific package), a status (not_affected, affected, fixed, or under_investigation), and a justification for that status. The justification is what makes VEX useful: it is not just a status flag, it is a documented reason that downstream tools and customers can act on.
VEX statement example
{
"vulnerability": "CVE-2024-1234",
"product": "firmware-image-v2.1.0",
"status": "not_affected",
"justification": "vulnerable_code_not_present",
"impact_statement": "The affected function (libxml2 XPath evaluation) is not compiled into the image. ProteanOS builds libxml2 with --without-xpath."
}
This single statement eliminates the triage burden for every downstream consumer of your firmware.
VEX formats
OpenVEX
OpenVEX is a minimal, JSON-based format focused exclusively on VEX statements. It is designed to be attached to SBOMs (SPDX or CycloneDX), integrates well with automated tooling, and is straightforward to generate from a build pipeline. If you are just starting with VEX, this is the right format.
CSAF VEX
CSAF is a broader advisory framework that includes VEX as one of its profiles. A CSAF VEX document is more verbose - it includes a product tree, advisory metadata, and a built-in distribution and trust model - which is exactly what regulatory bodies such as CISA and European authorities expect to see. It is also what larger customers increasingly require when they ask for a vulnerability disclosure process.
For most embedded teams, the pragmatic approach is to use OpenVEX internally and for SBOM distribution, and to produce CSAF VEX for regulatory submissions and formal customer disclosures.
Generating VEX at build time
The most efficient approach is generating VEX statements during the build process, when you know exactly what is compiled and configured.
From Yocto
Yocto 5.2's cve-check class can generate VEX statements for packages where the CVE check determines "not affected" based on version ranges or patch status. See the Yocto 5.2 highlights for details.
From build configuration
For vulnerabilities that depend on compile-time configuration (e.g., a feature compiled out), generate VEX statements from your build configuration:
# Pseudocode: generate VEX from config
if not config.has("LIBXML2_XPATH"):
vex.add_statement(
cve="CVE-2024-1234",
status="not_affected",
justification="vulnerable_code_not_present",
detail="XPath support disabled at compile time"
)
From runtime analysis
Some "not affected" determinations require runtime context (e.g., the vulnerable network service is not started). These are harder to automate but can be captured in VEX statements with appropriate justifications.
Justification categories
The VEX specification defines standard justification categories for "not affected":
| Justification | When to use |
|---|---|
component_not_present | The vulnerable package is not included in the image |
vulnerable_code_not_present | The package is present but the vulnerable code (function, module) is not compiled in |
vulnerable_code_not_in_execute_path | The code is compiled in but never executed in your product's configuration |
inline_mitigations_already_exist | The vulnerability is mitigated by other controls (sandboxing, network isolation, etc.) |
Choose the most specific justification. vulnerable_code_not_present is stronger than vulnerable_code_not_in_execute_path because it is deterministic rather than depending on runtime configuration.
Distribution
Attach to SBOMs
The recommended approach is distributing VEX documents alongside your SBOM. The firmware SBOM documentation covers SBOM generation and distribution.
SPDX 3.0 can embed VEX statements directly in the SBOM document using the Security profile. CycloneDX has a VEX extension.
CSAF distribution
CSAF advisories are published at well-known URLs following the CSAF provider specification:
https://example.com/.well-known/csaf/provider-metadata.json
https://example.com/.well-known/csaf/2026/csaf-2026-001.json
This allows automated tools to discover and consume your advisories.
Frequency
Publish VEX updates when:
- A new firmware version is released (include VEX for all known CVEs)
- A new CVE is published that affects a package in your image
- Your triage determines a previously "under investigation" CVE is not affected
Scaling across product families
When you maintain multiple products sharing common packages, VEX statements for shared components can be reused:
- Generate per-package VEX statements at the build system level
- Aggregate per-product VEX documents by combining package-level statements
- Publish product-level VEX documents
This avoids duplicating triage work across products. A "not affected" determination for libssl 3.1.4 with XPath disabled applies to every product using the same configuration.
Integration with ProteanOS
ProteanOS's packaging metadata includes fields for security information. VEX statements can reference ProteanOS package identifiers directly.
The SLSA build provenance documentation workflow produces the build evidence that supports VEX justifications. When you claim "vulnerable code not present," the build provenance proves which configuration flags were active.
For compliance with the EU Cyber Resilience Act, the EU CRA compliance guide covers how VEX fits into the broader evidence pack.
Where to start
If your team currently has no VEX process, the most useful first step is not picking a format - it is identifying the top 20 CVEs in your current scanner output and writing VEX statements for them manually. That exercise reveals which justification categories apply to your build, which packages need recurring attention, and where your build configuration can be made more precise. From there, automating statement generation from your build system is a natural next step. The format choice (OpenVEX or CSAF) matters less than having a repeatable process that produces statements with accurate, defensible justifications.