From software inventories to defensible vulnerability-exploitability decisions
A technical tutorial on SBOMs and Vulnerability Exploitability eXchange, covering CISA semantics, CSAF, CycloneDX, SPDX, OpenVEX, Log4Shell, automation, interoperability, and practical use under the EU Cyber Resilience Act.
cybersecurity
regulation and compliance
software development
tutorial
🇬🇧
Author
Affiliation
Antonio Montano
4M4
Published
December 3, 2022
Modified
August 22, 2026
Abstract
Software Bills of Materials (SBOMs) and Vulnerability Exploitability eXchange (VEX) address different stages of the software-vulnerability lifecycle. An SBOM establishes a structured representation of software composition; it does not determine whether every vulnerability associated with an included component affects the finished product. VEX addresses that second problem by communicating a scoped product-specific assessment: whether a vulnerability is affected, not affected, fixed, or under investigation, together with the justification, impact, or action information needed to interpret that conclusion. Starting from this separation, the article develops an end-to-end model that links product identity, SBOM evidence, vulnerability correlation, technical investigation, assessment, VEX publication, consumer acceptance, reassessment, and auditable vulnerability disposition.
The article then compares the principal VEX implementation architectures as distinct semantic models rather than interchangeable serializations. CSAF embeds VEX in a structured security-advisory framework; CycloneDX integrates applicability and product-impact analysis into a Bill-of-Materials model; SPDX 3 represents VEX through first-class typed security relationships; and OpenVEX provides a lightweight, SBOM-agnostic statement format. Their concepts overlap, but product identity, status vocabularies, justification taxonomies, remediation semantics, provenance, version applicability, and lifecycle information do not map one-to-one. A worked analysis of CVE-2021-44228 shows why component presence, vulnerable-code presence, reachability, adversary control, mitigation, remediation, and uncertainty must remain distinct before a defensible VEX conclusion can be issued. The implementation discussion extends this analysis into CI/CD automation, trust boundaries, interoperability, semantic-loss handling, reversible suppression, and consumer-side acceptance policy. A dedicated CycloneDX 1.7 implementation appendix then moves from architecture to field-level practice, explaining how document identity, product identity, affects, version applicability, analysis, justifications, lifecycle metadata, provenance, completeness, signatures, producer profiles, and consumer validation interact in a defensible VEX workflow.
The Cyber Resilience Act (CRA) gives this distinction practical regulatory significance in the European context. Regulation (EU) 2024/2847 incorporates SBOM creation into manufacturers’ vulnerability-handling obligations under the full CRA regime, while it does not mandate VEX or any particular VEX serialization. VEX can nevertheless support CRA operations by communicating product-specific vulnerability conclusions, improving supplier and product-security workflows, and contributing evidence to Article 14 reporting decisions. It cannot, by itself, establish active exploitation, legal reportability, conformity, or the absence of remediation obligations. The resulting implementation principle is that software-composition evidence, product-specific vulnerability assessment, VEX communication, exploitation or incident evidence, and regulatory decision records should remain distinct but traceably connected. Safe automation therefore depends on precise product identity, evidence-backed assessments, authenticated and authorized issuers, preservation of semantic scope, explicit conflict handling, reversible disposition changes, and reassessment whenever the assumptions underlying a VEX statement cease to hold.
A technical tutorial on SBOMs and Vulnerability Exploitability eXchange, covering CISA semantics, CSAF, CycloneDX, SPDX, OpenVEX, Log4Shell, automation, interoperability, and practical use under the EU Cyber Resilience Act.
Why SBOMs need VEX
A vulnerability scanner starts from a correlation problem. A product contains software components, vulnerability intelligence associates some of those components or versions with known vulnerabilities, and the scanner reports matches. The difficulty begins when a match is interpreted as though it were already a product-security conclusion.
CISA’s current SBOM guidance defines an SBOM as a formal record of software components and their supply-chain relationships. Its 2025 minimum-elements update expands the older U.S. baseline with fields and operational attributes intended to make SBOMs more useful for vulnerability management, including component hashes, license information, tool identity, generation context, coverage expectations, and explicit treatment of unknown dependencies.1 The earlier NTIA minimum-elements report established the widely used baseline of supplier, component name, version, identifiers, dependency relationships, SBOM author, and timestamp.2 ENISA has likewise treated SBOMs as a mechanism for software-component transparency and vulnerability-management support in European cybersecurity guidance.3
The essential point is that an SBOM records composition. Let a product P have an SBOM-represented component set
S(P)={C_1,C_2,\ldots,C_n}.
Let M(V,C) be a vulnerability-intelligence relation that is true when vulnerability V is associated with component C. A scanner finding is then approximately
It establishes only a candidate vulnerability finding. The difference can arise for many reasons:
the vulnerable component may not actually be present in the shipped artifact even though it appeared earlier in the build process;
the component may be present but the vulnerable code may have been removed;
vulnerable code may be present but unreachable;
the vulnerable path may require attacker control that the product does not expose;
a product-integrated mitigation may prevent exploitation;
the component-to-vulnerability match itself may be incorrect;
the product may already incorporate a corrective release.
CISA’s VEX work addresses precisely this gap. VEX is designed to communicate whether a vulnerability actually affects a product and to distinguish product-specific states such as AFFECTED, NOT AFFECTED, FIXED, and UNDER INVESTIGATION.4
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart LR
B[SBOM]
I[Vulnerability<br/>intelligence]
C(Vulnerability<br/>correlation)
K[Candidate<br/>vulnerabilities]
A(Technical<br/>assessment)
X[VEX]
B -. evidence .-> C
I -. evidence .-> C
C --> K
K --> A
A --> X
Figure 1: A semantically typed pipeline from software inventory to product-specific vulnerability communication.
Figure 1 shows that the SBOM is an artefact, not a process. Candidate vulnerabilities are intermediate findings, not final conclusions. Technical assessment is the decisive transformation that turns correlation into a product-specific judgment. VEX is the resulting communication artefact.
The SBOM answers:
What software is represented in this product?
Vulnerability intelligence asks:
Which known vulnerabilities are associated with those components?
The technical assessment asks:
Does the vulnerability actually affect this product?
VEX communicates:
What did the assessor conclude, for which product and vulnerability, and with what status or justification?
This article’s central thesis follows from that separation: SBOM plus vulnerability matching is an identification process; VEX is a product-specific decision and communication process. Confusing the two produces either excessive false positives or dangerous false negatives.
What an SBOM represents: components, identities, and dependency graphs
An SBOM should not be treated as a flat list of package names. A useful model includes component records, dependency relationships, metadata about how the SBOM was generated, and identifiers precise enough to support downstream correlation.
Represent an SBOM for product P, observed at time t and generated in context g, as
\mathcal{C}_P is the set of represented component records;
\mathcal{R}_P is the set of dependency or composition relationships;
\mathcal{M} is document and generation metadata.
CISA’s 2025 minimum-elements publication explicitly adds Generation Context, describing whether the SBOM was produced before, during, or after build, and expects enough coverage for recipients to understand whether dependency information is complete.5 That information changes what can safely be inferred from the SBOM.
Component identity is a security control
A conceptual component identity can be written as
I(C)=(e,n,v,q,h),
\tag{3}
where:
e is the package ecosystem or identifier namespace;
n is the package name;
v is the version;
q represents qualifiers or other identity attributes;
h represents cryptographic hashes where appropriate.
The Package URL specification, standardized as ECMA-427 in 2025, provides a package-oriented identifier for ecosystems such as Maven, npm, PyPI, OCI, Debian, and others.6 CPE provides a different standardized naming system oriented toward product classes in security automation.7
Neither identifier is universally sufficient. PURL may identify a package precisely while still omitting a locally patched binary. CPE may identify a vendor product family while being too coarse for a particular dependency artifact. Hashes can establish byte-level identity but are poor discovery keys across rebuilt or repackaged artifacts.
The practical requirement is not to choose one identifier universally. It is to preserve enough identity information that a vulnerability assertion can be matched to the same software object on both producer and consumer sides.
Dependencies form a graph
Let
G_P=(\mathcal{C}_P,\mathcal{R}_P)
\tag{4}
be the dependency graph of product P. A direct dependency is connected by one dependency edge. A transitive dependency is reached through one or more intermediate nodes.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart LR
P[Product P]
A[Library A<br/>direct dependency]
B[Library B<br/>direct dependency]
C[Library C<br/>transitive dependency]
V[Vulnerability V]
P -->|depends on| A
P -->|depends on| B
A -->|depends on| C
V -. associated with .-> C
Figure 2: An SBOM dependency graph distinguishes the product, direct dependencies, and transitive dependencies, while a separate vulnerability association identifies which dependency becomes a candidate for later assessment.
In Figure 2 the product and libraries remain artefact nodes; the vulnerability remains an external information node; and the dashed edge indicates that the vulnerability association is evidentiary and contextual rather than a final product judgment. The graph matters because a vulnerability can originate several layers below the top-level product while the eventual VEX conclusion still concerns the final product.
Presence has several meanings
An SBOM reflects the context in which it was generated, so the notion of component presence must be interpreted carefully. An SBOM derived from source manifests may include dependencies that never reach the shipped product, while one captured at an intermediate build stage may differ from the final package. Conversely, a runtime inventory may miss modules that are downloaded dynamically, and a container SBOM may accurately describe the image itself while excluding plug-ins or other components mounted from the surrounding environment.
Consequently,
C\in\mathcal{C}_P
must always be interpreted relative to the SBOM’s generation context and coverage.
A useful SBOM assurance model distinguishes:
validity: does the document conform to its format?
correctness: are represented facts accurate?
completeness: are relevant components missing?
freshness: does it still describe the artifact in question?
identity precision: can represented components be matched safely?
VEX cannot repair a poor SBOM. If the inventory falsely says that a vulnerable component is absent, an automated component_not_present conclusion can become a correlated false negative.
From CVE match to VEX decision: the end-to-end process
The correct VEX process begins when vulnerability correlation produces a candidate, not when a serializer is invoked. Let \mathcal{V} be the vulnerability set known to the scanner. The candidate set for product P is
Each (C,V)\in K(P) requires a scoped product assessment.
Scope the product before analysing exploitability
The assessed object should normally be more precise than a marketing product name. Let
P_{r,a}
denote release r and artifact or deployment variant a of product P.
This distinction prevents an assertion about Product 5.2 / Linux x86_64 container digest X from silently applying to Product 5.2 / Windows installer or to a rebuilt container carrying different dependencies.
Model the vulnerability preconditions
Let R_V denote the technical conditions required for the vulnerable behaviour of V. Evidence about the product can then be represented as
Table 1: Evidence classes that can support a VEX assessment.
A simplified assessment function is
A(P,V,E,t)\rightarrow(s,j,i,a),
\tag{6}
where:
s is status;
j is a structured justification where applicable;
i is impact information;
a is action information;
t is the assessment time.
The portable VEX statement is a projection of a richer internal case record, not the entire case file.
The lifecycle is iterative
A defensible VEX workflow is iterative rather than purely linear. The initial path begins with a product artefact and its SBOM, continues through vulnerability correlation, and produces a candidate finding. That finding is then investigated using product-specific evidence before an assessment outcome is issued as a VEX assertion. Once published, however, the lifecycle does not end: downstream systems consume the VEX, and the assertion may later need revision when the product changes, new technical evidence appears, or vulnerability intelligence is updated.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart TD
P[Product artefact]
B[SBOM]
I[Vulnerability<br/>intelligence]
C(Vulnerability<br/>correlation)
K[Candidate<br/>finding]
E[Evidence<br/>package]
A(Technical<br/>investigation)
O{Assessment<br/>outcome}
X[VEX assertion]
U(Vulnerability-management<br/>consumption)
PC[Product<br/>change]
NE[New<br/>evidence]
UI[Updated vulnerability<br/>intelligence]
R(Reassessment)
P --> B
B -. evidence .-> C
I -. evidence .-> C
C --> K
K --> A
E -. evidence .-> A
A --> O
O -->|AFFECTED / NOT AFFECTED / FIXED / UNDER INVESTIGATION| X
X --> U
PC -. trigger .-> R
NE -. trigger .-> R
UI -. trigger .-> R
R --> A
Figure 3: A defensible VEX lifecycle begins with artefact inventory and vulnerability correlation, continues through technical investigation and assessment, publishes a VEX assertion, and then re-enters reassessment when the product, evidence base, or vulnerability intelligence changes.
CISA’s guidance treats VEX as time-dependent security information: an assertion reflects the supplier’s assessment of a particular product-vulnerability pair at a particular point in time and should be updated when the underlying knowledge changes.8
A VEX statement should therefore be read as a time-scoped record binding together the product, vulnerability, current status, any applicable justification, impact or action information, and the time at which the assessment was valid. Time is not incidental metadata: it is part of the meaning of the assertion.
The lifecycle is better represented as a progression of records and reassessment processes than as an algebraic expression:
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart LR
U[UNDER INVESTIGATION<br/>VEX assertion]
R(Technical<br/>reassessment)
O{Current assessment<br/>outcome}
A[AFFECTED<br/>VEX assertion]
N[NOT AFFECTED<br/>VEX assertion]
M(Remediation)
F[FIXED<br/>VEX assertion]
E[New technical<br/>evidence]
P[Product or<br/>configuration change]
I[Updated vulnerability<br/>intelligence]
U --> R
E -. evidence .-> R
P -. trigger .-> R
I -. evidence .-> R
R --> O
O -->|Affected| A
O -->|Not affected| N
A --> M
M --> F
Figure 4: VEX assertions evolve as technical knowledge changes. An initial under-investigation assertion is reassessed when evidence improves, producing either an affected or not-affected assertion; an affected product can later progress to a fixed assertion after remediation.
In Figure 4, the VEX states are persistent assertions that can be published and consumed. Technical reassessment updates the organisation’s knowledge of the product’s security state, whereas remediation can change that state itself. The assessment outcome represents a decision, while new evidence, product changes, and revised vulnerability intelligence enter as evidentiary or triggering inputs.
The two principal paths are therefore:
Investigation → affected → remediation → fixed, when the technical assessment confirms product impact and a corrective change is subsequently incorporated;
Investigation → not affected, when sufficient evidence establishes that the vulnerability does not affect the assessed product.
A later VEX assertion does not necessarily mean that the earlier one was incorrect. UNDER INVESTIGATION, for example, can have been an accurate representation of the available knowledge at the time it was issued. A subsequent AFFECTED, NOT AFFECTED, or FIXED statement records a change either in knowledge about the product or in the product itself. The operational requirement is therefore not to overwrite that history silently, but to preserve enough temporal and provenance information to determine which assertion applies to which product state and at what time.
CISA VEX semantics: status, justification, and evidence
CISA’s minimum requirements provide an implementation-neutral semantic core. The four principal statuses are:
Abstractly, a VEX assessment can be represented as
(P,V)\mapsto(s,j,i,a).
\tag{7}
Here, P denotes the specific product or product version being assessed, V the vulnerability, s the resulting VEX status, j a structured justification where applicable, i additional impact information, and aaction or remediation information.
The mapping should therefore be read as: for vulnerability V and product P, the assessment produces status s, together with the justification, impact information, and action information needed to qualify that status. Not every output field is meaningful in every state. A NOT AFFECTED statement must provide either a structured justification or, if no justification is provided, an impact statement explaining why the product is not affected. An AFFECTED statement must include an action statement describing the recommended remediation, mitigation, or other response.
The four states answer different questions
Status
Meaning
Operational implication
NOT AFFECTED
The defined product does not require remediation for the vulnerability within the asserted scope
A justification or impact explanation is required
AFFECTED
The defined product is affected
An action statement is required
FIXED
The defined product version contains a correction for the vulnerability
Consumers should treat the status as product/version-specific
UNDER INVESTIGATION
Impact has not yet been determined
Uncertainty is explicit; the finding should not be interpreted as safe
Table 2: Implementation-neutral interpretation of the four CISA VEX statuses.
UNDER INVESTIGATION is epistemic. It says something about what is known, not about severity. FIXED is version-scoped. It does not mean the product is secure against every other vulnerability. NOT AFFECTED is stronger than:
no exploitation has been observed;
the CVE is low priority;
an external firewall reduces exposure;
the scanner did not detect the issue.
The five standardized NOT AFFECTED justifications
CISA recommends five machine-readable justifications:10
These can be interpreted against a simplified exploitability model. Let:
C mean the vulnerable component is present;
K mean the vulnerable code is present;
R mean the vulnerable code is reachable;
U mean the attacker controls the required input or state;
\mu mean a built-in mitigation prevents exploitation.
A simplified affected condition is
C\land K\land R\land U\land\neg\mu.
\tag{8}
Each negative justification negates a different part of that chain.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart TD
C{Vulnerable component<br/>present?}
K{Vulnerable code<br/>present?}
R{Vulnerable code in<br/>execution path?}
A{Adversary controls<br/>required input or state?}
M{Built-in mitigation<br/>prevents exploitation?}
N1[NOT AFFECTED<br/>component_not_present]
N2[NOT AFFECTED<br/>vulnerable_code_not_present]
N3[NOT AFFECTED<br/>vulnerable_code_not_in_execute_path]
N4[NOT AFFECTED<br/>vulnerable_code_cannot_be_controlled_by_adversary]
N5[NOT AFFECTED<br/>inline_mitigations_already_exist]
Y[Potentially AFFECTED<br/>candidate conclusion]
C -->|No| N1
C -->|Yes| K
K -->|No| N2
K -->|Yes| R
R -->|No| N3
R -->|Yes| A
A -->|No| N4
A -->|Yes| M
M -->|Yes| N5
M -->|No| Y
Figure 5: The five CISA NOT AFFECTED justifications correspond to distinct decision points at which exploitability can fail.
This tree maps the semantics of the five justifications to distinct exploitability preconditions; it is not a complete evidentiary decision procedure. If a required predicate cannot yet be established as true or false, the assessment remains vUNDER INVESTIGATION rather than defaulting to either AFFECTED or NOT AFFECTED.
The assessment model in Equation 6 keeps evidence and justification in different roles. Evidence E(P,V) is an input to the assessment; the structured justification j is one output of that assessment and is therefore a classification supported by evidence, not the evidence package itself.
For example, a serializer or schema validator can establish that vulnerable_code_not_in_execute_path is an allowed justification value. It cannot establish the technical proposition encoded by that value: that the vulnerable code is in fact absent from every relevant execution path. Schema validity therefore establishes syntactic conformance only; the truth of the VEX claim remains dependent on the underlying evidence and assessment.
This distinction remains valid for every concrete VEX implementation.
CSAF: VEX as a structured security advisory
The Common Security Advisory Framework (CSAF) is an OASIS standard for structured machine-readable security advisories. CSAF 2.0 was approved as an OASIS Standard in 2022 and contains a dedicated VEX profile.11 As of 22 August 2026, CSAF 2.1 remains at Committee Specification Draft 02; it should therefore not be described as a finalized replacement for the 2.0 OASIS Standard.12
CSAF is broader than VEX. Its natural abstraction is
X_{\mathrm{CSAF}}=(D,T,\mathcal{V}),
\tag{9}
where:
D is advisory/document metadata;
T is a product tree;
\mathcal{V} is a set of vulnerability objects.
Product identity lives in the product tree
CSAF’s product tree can represent vendors, product families, product names, versions, and relationships. Vulnerability objects do not generally repeat those complete identities; they reference document-local Product IDs.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart LR
X[CSAF VEX document]
D[Document metadata]
T[Product tree<br/>Product IDs]
V[Vulnerability object]
S[product_status<br/>Product ID references]
F[flags / impact]
R[remediations]
X --> D
X --> T
X --> V
V --> S
V --> F
V --> R
T -. references Product IDs .-> S
T -. references Product IDs .-> F
T -. references Product IDs .-> R
Figure 6: CSAF VEX is an advisory-centred document model: the document contains metadata, a product tree, and vulnerability objects, while vulnerability-specific structures refer back to product identities defined in the tree.
This is an advisory-centred architecture. The consumer first resolves the Product ID into the product tree and then determines whether that product matches the asset being evaluated.
CSAF has richer product-status semantics than the four CISA labels
CSAF 2.0 includes a richer product-status vocabulary than the four CISA states:
known_affected: the product is known to be affected by the vulnerability.
known_not_affected: the product is known not to be affected.
fixed: the product contains a fix for the vulnerability.
under_investigation: the product’s vulnerability status has not yet been determined.
first_affected: the first product version known to be affected.
first_fixed: the first product version known to contain a fix.
last_affected: the last product version known to be affected.
recommended: the product version recommended as the remediation target.13
The approximate mapping is:
CISA concept
CSAF 2.0 representation
AFFECTED
known_affected
NOT AFFECTED
known_not_affected
FIXED
fixed, with first_fixed or recommended providing additional release-train semantics
UNDER INVESTIGATION
under_investigation
Table 3: Core CISA-to-CSAF VEX status mapping.
The mapping is semantic, not textual. CSAF’s vocabulary can represent more information about release history than the four-state CISA abstraction.
CSAF carries justification through VEX flags and supporting structures
For a known_not_affected product, CSAF can associate VEX-relevant flags such as component_not_present with specific product IDs. Impact statements can further explain why the product is not affected.
CSAF is therefore attractive when VEX is part of a broader vendor advisory process. It can express product families, version progressions, remediations, advisory revisions, and vulnerability status in one structured document. Its cost is correspondingly higher: product trees and advisory semantics must be built and interpreted correctly.
CycloneDX: VEX in a Bill-of-Materials ecosystem
CycloneDX takes a different route. Its primary object is the Bill of Materials rather than the security advisory.
As of 22 August 2026, CycloneDX 1.7 remains the current stable BOM specification. CycloneDX 2.0 has been announced for later in 2026, but the project’s specification pages still identify 1.7 as the stable version.14 CycloneDX 1.7 is standardized as ECMA-424, second edition.15
A simplified model is
X_{\mathrm{CDX}}=(B,\mathcal{V}),
\tag{10}
where B is the broader BOM and \mathcal{V} is the vulnerability collection.
bom-ref links vulnerability information to BOM objects
Components and services have bom-ref identifiers that can be referenced elsewhere in the BOM. The vulnerability object’s affects structure can point to those objects.16
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart LR
B[CycloneDX BOM]
C[Components + services<br/>dependencies]
I[Object identity<br/>bom-ref]
V[Vulnerability collection]
F[affects<br/>target + version status]
A[analysis<br/>state + justification<br/>response + detail]
B --> C
B --> V
C --> I
V --> F
V --> A
I -. references bom-ref .-> F
Figure 7: CycloneDX VEX reuses identities already defined in the BOM, expresses vulnerability applicability through affects references to BOM objects, and carries assessment semantics in the vulnerability analysis object.
This is particularly convenient when the organisation already has CycloneDX identities, dependency relationships, hashes, PURLs, pedigree, and other supply-chain metadata.
Version applicability and analysis state are different dimensions
The affects structure expresses whether a particular version of the referenced BOM object falls within the vulnerability’s applicability range:
affected: the version is considered affected by the vulnerability.
unaffected: the version is considered outside the affected range.
unknown: applicability to the version has not been determined.
The analysis.state field represents a different dimension: the current outcome or stage of the product-specific vulnerability analysis. In CycloneDX 1.7 it includes:17
resolved: the vulnerability has been addressed and the analysis is considered complete.
resolved_with_pedigree: the vulnerability has been resolved and the corrective change is represented through component pedigree.
exploitable: analysis has determined that the vulnerability is exploitable in the assessed context.
in_triage: the vulnerability is still being investigated.
false_positive: the reported vulnerability association is considered incorrect.
not_affected: the vulnerability is valid, but the assessed product or component is not affected.
An approximate crosswalk is:
CISA concept
CycloneDX 1.7
AFFECTED
exploitable
NOT AFFECTED
not_affected
FIXED
resolved
FIXED with explicit corrective pedigree
resolved_with_pedigree
UNDER INVESTIGATION
in_triage
No exact CISA core equivalent
false_positive
Table 4: CISA concepts and CycloneDX 1.7 impact-analysis states are related but not identical.
false_positive deserves special attention. It can mean that the vulnerability association itself was erroneous:
\neg M(V,C),
which is different from a valid component-vulnerability association that turns out not to affect the final product.
CycloneDX justifications are not the CISA five
CycloneDX 1.7 provides a broader justification vocabulary for explaining why an assessed vulnerability is considered not_affected:18
code_not_present: the vulnerable code is not present in the assessed component or product.
code_not_reachable: the vulnerable code is present but cannot be reached through the relevant execution paths.
requires_configuration: exploitation requires a configuration that is not present in the assessed environment.
requires_dependency: exploitation depends on another component or dependency that is absent.
requires_environment: exploitation requires environmental conditions that are not present.
protected_by_compiler: compiler-generated protections prevent the vulnerable behaviour from being exploitable.
protected_at_perimeter: perimeter controls prevent the vulnerable functionality from being reached through the relevant attack path.
protected_by_mitigating_control: another mitigating control prevents exploitation in the assessed context.
Some map closely to CISA concepts; others do not.
CycloneDX
Closest CISA concept
Caveat
code_not_present
vulnerable_code_not_present
Strong correspondence
code_not_reachable
vulnerable_code_not_in_execute_path
Strong if reachability evidence is equivalent
requires_configuration
Context-dependent
Not a universal CISA mapping
protected_at_perimeter
No exact CISA equivalent
Environmental protection is not necessarily an inline product mitigation
protected_by_mitigating_control
Sometimes related to inline mitigation
CycloneDX is broader
Table 5: CycloneDX justification semantics do not form a one-to-one mapping to CISA VEX.
A converter must therefore satisfy more than lexical similarity. If J_C is a CycloneDX justification and J_T the target justification, a safe conversion requires every claim entailed by the target representation to remain supported by the source semantics. If the target would assert more than the source justifies, the mapping is unsafe because it strengthens the claim.
component_not_present exposes an interoperability gap
CycloneDX 1.7 does not have an exact core justification equivalent to CISA’s component_not_present. Mapping it to code_not_present can be wrong because
\neg C
and
C\land\neg K
are distinct propositions.
A safe CycloneDX representation can preserve analysis.state = not_affected and put the component-absence reason into analysis.detail rather than manufacturing a different structured justification. This is an example of correct but lossy serialization.
SPDX 3: VEX in the Security Profile
SPDX 3 represents VEX using typed graph relationships. As of 22 August 2026, SPDX 3.0.1 remains the stable 3.x baseline. SPDX 3.1-RC1, released in January 2026, is still described by the SPDX project as a pre-release intended for testing and validation.19
Let
G_{\mathrm{SPDX}}=(E,R)
\tag{11}
be an SPDX graph whose elements are E and relationships are R. A VEX assertion is represented as a typed relationship from a Vulnerability element to one or more product elements.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart LR
V[Vulnerability element]
A[VexAffectedVulnAssessmentRelationship<br/>affects]
N[VexNotAffectedVulnAssessmentRelationship<br/>doesNotAffect]
F[VexFixedVulnAssessmentRelationship<br/>fixedIn]
U[VexUnderInvestigationVulnAssessmentRelationship<br/>underInvestigationFor]
P["VEX product element(s)"]
C[Assessed SoftwareArtifact]
V --> A --> P
V --> N --> P
V --> F --> P
V --> U --> P
A -. assessedElement .-> C
N -. assessedElement .-> C
F -. assessedElement .-> C
U -. assessedElement .-> C
Figure 8: SPDX 3 represents each VEX status as a first-class typed relationship from a Vulnerability element to one or more elements representing VEX products; the relationship can additionally reference the software artifact actually assessed through assessedElement.
The SPDX Security Profile defines concrete VEX assessment relationship classes whose relationship types correspond closely to the four CISA states.20
Product and vulnerable component can remain distinct
SPDX’s assessedElement property is useful when vulnerability V originates in dependency C but the product-level VEX conclusion concerns P.
Conceptually:
V
\overset{\text{VEX status}}{\longrightarrow}
P,
while
\operatorname{assessedElement}=C.
This allows multiple products containing the same vulnerable component to receive different assessments without duplicating the vulnerability or component identity.
SPDX preserves the five CISA justifications closely
VexJustificationType closely mirrors the five CISA NOT AFFECTED justifications, using SPDX’s camelCase naming convention:21
componentNotPresent: the vulnerable component is not present in the assessed product.
vulnerableCodeNotPresent: the component may be present, but the vulnerable code is absent.
vulnerableCodeNotInExecutePath: the vulnerable code is present but is not reachable through an execution path relevant to the product.
vulnerableCodeCannotBeControlledByAdversary: exploitation requires input or state that an adversary cannot control in the assessed product.
inlineMitigationsAlreadyExist: built-in mitigations already prevent exploitation of the vulnerability.
The mapping is consequently much less lossy than the CycloneDX justification crosswalk. A not-affected relationship must provide appropriate explanation through structured justification or an impact statement, while affected relationships carry action information. SPDX also makes the relationship itself a first-class element with provenance, timestamps, notes, and VEX-version information.
Because the VEX assessment relationship is itself a first-class SPDX element, it can carry its own identifier, status-specific information, provenance, timestamps, notes, and VEX-version metadata. Its lifecycle can therefore be managed independently of the surrounding SBOM graph.
That is the core architectural advantage of SPDX VEX: the assessment is a reusable graph object rather than merely a field nested inside a vulnerability record.
OpenVEX: minimal and SBOM-agnostic assertions
OpenVEX occupies the minimalist end of the spectrum. Its design starts with the VEX statement rather than with an advisory, a BOM, or a general knowledge graph. As of 22 August 2026, the OpenVEX repository still describes the specification as a draft, with v0.2.0 remaining the latest tagged specification release.22
OpenVEX defines four status values that closely follow the CISA VEX state model:
not_affected: the assessed product is not affected by the vulnerability.
affected: the assessed product is affected by the vulnerability.
fixed: the vulnerability has been corrected in the assessed product version.
under_investigation: the product’s vulnerability status has not yet been determined.
Its five standard not_affected justifications likewise mirror the CISA labels directly.23 This makes OpenVEX attractive when a team wants a small interchange layer around an existing internal assessment model.
A simplified document is:
{"@context":"https://openvex.dev/ns/v0.2.0","@id":"https://example.invalid/vex/42","author":"Example Product Security Team","timestamp":"2026-08-21T08:00:00Z","version":1,"statements":[{"vulnerability":{"name":"CVE-YYYY-NNNN"},"products":[{"@id":"pkg:generic/example-product@4.2.0"}],"status":"not_affected","justification":"component_not_present","impact_statement":"The vulnerable component is absent from the release artifact."}]}
SBOM-agnostic does not mean identity-agnostic
OpenVEX does not require the product to be a CycloneDX object, an SPDX element, or a CSAF Product ID. The product structure can instead carry software identifiers such as PURL or CPE and can identify subcomponents.24
The consumer must still establish that the identity of the local asset Q matches the identity asserted for OpenVEX product P:
A weak marketing name does not become a safe identity simply because the VEX format is simple.
Time is part of the statement
OpenVEX explicitly treats VEX statements as time-scoped knowledge. For the same product-vulnerability pair, the current assessment can move from under_investigation to affected and, after a corrective product change, to fixed.
Consumers should therefore select the most recent statement that is applicable to the same product and vulnerability scope and trusted under local policy, not simply the statement contained in the newest file.
OpenVEX’s minimality is its principal strength and its principal boundary. It is well suited to separately distributed VEX feeds and attestations, but projection from richer formats can discard advisory, pedigree, release-history, or graph semantics.
Worked case: CVE-2021-44228 and the Log4Shell VEX pipeline
CVE-2021-44228, commonly called Log4Shell, demonstrates why an SBOM match and a VEX conclusion are different propositions. Apache’s security documentation identifies the affected component as log4j-core, not every artifact whose name contains log4j, and documents the affected and fixed version ranges for CVE-2021-44228.25 Spring’s response likewise distinguished Spring Boot applications using the default logging configuration from applications explicitly switched to Log4j2.26 CISA included CVE-2021-44228 in the Known Exploited Vulnerabilities catalog, establishing that exploitation was not merely hypothetical.27
Step 1: distinguish package identities
For this CVE, neither the presence of log4j-api nor the presence of log4j-to-slf4j implies that the product is affected. The security-relevant condition is the presence of a vulnerable log4j-core release.
A useful inventory can distinguish pkg:maven/org.apache.logging.log4j/log4j-api@2.14.1 from pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1.
A scanner that normalizes both to Log4j has already lost information needed for a defensible VEX decision.
Product state A: vulnerable component absent
Let P_A be a Spring Boot application using the default starter logging configuration. Its release artifact contains logback-classic, log4j-api, and log4j-to-slf4j, but not log4j-core.
Suppose this absence is established from an artifact-bound SBOM and confirmed by inspection of the released artifact. Because CVE-2021-44228 concerns vulnerable versions of log4j-core, the component-presence condition C in Equation 8 is false for this product state.
The appropriate VEX assessment is therefore NOT AFFECTED, with the structured justification component_not_present.
The scope of that assertion matters. It does not establish that Spring Boot as a technology is unaffected by Log4Shell. It establishes only that the specifically identified application artifact P_A is not affected by CVE-2021-44228 because the vulnerable component is absent.
Product state B: vulnerable log4j-core in an exploitable path
Let P_B be an application configured to use Log4j2 and containing pkg:maven/org.apache.logging.log4j/log4j-core@2.14.1. Assume product analysis also establishes that attacker-controlled input can reach the relevant vulnerable logging behaviour and that no built-in mitigation prevents exploitation.
For this product state,
C=1,\quad K=1,\quad R=1,\quad U=1,\quad \mu=0.
The exploitability condition introduced in Equation 8 is therefore satisfied:
C\land K\land R\land U\land\neg\mu=1.
The appropriate VEX assessment is AFFECTED. The resulting VEX statement must also include an action statement describing the recommended remediation or mitigation, such as upgrading to an appropriate corrected version of log4j-core.
Product state C: the CVE-specific fix is incorporated
Let P_C be the corrected product state using a Log4j release that Apache identifies as fixing CVE-2021-44228 for the relevant Java branch.28
The appropriate VEX assessment for this product state is therefore FIXED. The status is scoped to both the identified product state P_C and CVE-2021-44228: it establishes that this vulnerability has been corrected in that product state, not that the Log4j dependency is free from every other vulnerability.
That distinction became operationally important because Apache subsequently documented CVE-2021-45046 and other vulnerabilities that led to further upgrade recommendations.29
Product state U: insufficient evidence
If the organisation has begun investigating a coarse inventory match for log4j but cannot yet determine whether log4j-core is present, the appropriate status is UNDER INVESTIGATION. This is particularly important during an emergency. Uncertainty must not be encoded as safety.
The evidence chain
The four product states above can be organized around one evidentiary sequence. The analysis starts with component identity and version applicability, then moves to product-specific questions about runtime use and attacker control. Once an assessment is underway, insufficient evidence at any stage yields UNDER INVESTIGATION; NOT AFFECTED is justified only when evidence establishes that an exploitability precondition is false. Failure to establish exploitability is not itself evidence of non-exploitability.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart TD
A[Runtime SBOM +<br/>artifact-inspection evidence]
B{log4j-core<br/>present?}
C{Version in<br/>affected range?}
H{Release history indicates<br/>corrected version?}
D(Analyse active logging<br/>implementation)
E(Trace attacker-controlled<br/>data to vulnerable behaviour)
Q{Exploitability conditions<br/>established?}
N1[NOT AFFECTED<br/>component_not_present]
N2[NOT AFFECTED<br/>version outside affected range]
F[FIXED<br/>corrected version for this CVE]
N3[NOT AFFECTED<br/>evidence-backed justification]
Y[AFFECTED<br/>product-specific conclusion]
U[UNDER INVESTIGATION<br/>evidence insufficient]
A -. evidence .-> B
B -->|No| N1
B -->|Yes| C
B -->|Unknown| U
C -->|No| H
C -->|Yes| D
C -->|Unknown| U
H -->|No| N2
H -->|Yes| F
D --> E
E --> Q
Q -->|Established| Y
Q -->|Disproved with evidence| N3
Q -->|Unresolved| U
Figure 9: For Log4Shell, component identity and version matching precede product-specific exploitability analysis; unresolved evidence remains UNDER INVESTIGATION rather than being converted into a not-affected conclusion.
One assessment, four serializations
For product state P_A, the underlying assessment is the same regardless of serialization: CVE-2021-44228 is NOT AFFECTED, with justification component_not_present. The conclusion is supported by artifact-bound inventory evidence establishing that log4j-core is absent from the assessed release artifact.
CycloneDX can express the product-level not_affected state but lacks an exact core component_not_present justification in 1.7; preserving the reason in analysis.detail is safer than mapping it to a different structured reason.
Format
Product model
Not-affected representation
Component-absence reason
CSAF 2.0
Product tree and Product ID
known_not_affected
component_not_present flag
CycloneDX 1.7
BOM object / bom-ref
analysis.state = not_affected
Preserve in detail; no exact core enum
SPDX 3.0.1
Graph element
doesNotAffect VEX relationship
componentNotPresent
OpenVEX 0.2.0
Lightweight product object
status = not_affected
component_not_present
Table 7: The same Log4Shell assessment serialized through four VEX architectures.
The formats differ. The technical conclusion should not.
Automating VEX in CI/CD and vulnerability operations
The purpose of VEX automation is not to make findings disappear faster. It is to make approved, evidence-backed product-impact decisions reproducible and machine-actionable.
A dangerous pipeline converts a scanner finding directly into an automatic NOT AFFECTED disposition and then suppresses the finding. A defensible pipeline instead binds the released artifact to an SBOM, derives candidate findings through vulnerability correlation, collects product-specific evidence, performs and approves the assessment, emits VEX from that approved record, and changes downstream disposition only after the consumer has verified the assertion.
Separate observation, assessment, and policy
Observed technical facts belong in the evidence package E(P,V). The assessment function defined in Equation 6 uses that evidence to produce the technical result (s,j,i,a). A separate local-policy step then determines the operational disposition on the basis of that assessment and the consumer’s own rules.
The distinction can be illustrated with the Log4Shell example:
Observation: log4j-core 2.14.1 is present in the assessed product.
Assessment: CVE-2021-44228 is AFFECTED for that product state.
Policy: if the vulnerability is critical, the product is affected, and the release is Internet-facing, publication is blocked until the applicable release criteria are satisfied.
These layers answer different questions. The observation records what is technically known; the assessment determines what the vulnerability means for the product; policy determines what the organisation does about that result.
Risk acceptance belongs in the policy layer. It can alter the operational response to an AFFECTED assessment, but it must not rewrite the technical status as NOT AFFECTED.
Generate the SBOM from the artifact you release
For a container image, bind the SBOM to an immutable digest. Current Trivy documentation supports generating CycloneDX SBOMs from container images and scanning CycloneDX or SPDX SBOMs as vulnerability-analysis inputs.30
Artifact-bound SBOM plus trusted inventory or artifact inspection
vulnerable_code_not_present
Build, patch, source, or binary evidence
vulnerable_code_not_in_execute_path
Reachability analysis with documented coverage assumptions
vulnerable_code_cannot_be_controlled_by_adversary
Data-flow and trust-boundary evidence
inline_mitigations_already_exist
Demonstrated built-in mitigation effectiveness
Table 8: Example internal evidence policy for not-affected conclusions.
An internal NOT AFFECTED gate should therefore require all three conditions simultaneously: the required evidence is complete, the assessed product and vulnerability scope are valid, and the required approval has been obtained. Failure of any one condition should normally return the case to investigation.
The external VEX can contain the compact result. This asymmetry is intentional: the internal assessment record should preserve substantially more evidence, assumptions, provenance, and review context than the exported VEX statement.
Sign or attest across trust boundaries
Sigstore’s Cosign supports signed in-toto attestations and verification workflows.31 VEX can be distributed as an attestation predicate or through other authenticated channels.
A valid signature can authenticate the origin and integrity of a VEX assertion when the signing identity is trusted and correctly bound to the issuer. It cannot establish that the underlying technical assessment is correct. Cryptographic authenticity and claim truth are therefore separate properties.
Only then should VEX change a vulnerability’s operational disposition. Current Trivy documentation demonstrates why tool-specific assurance matters: VEX can be discovered from local files, SBOM references, repositories, or OCI-associated attestations, but the exact trust and matching behaviour depends on the discovery path and tool version.32
Suppression must remain reversible
Let:
F_{\mathrm{raw}} be all raw findings;
F_{\mathrm{suppressed}} be findings modified by accepted VEX;
F_{\mathrm{actionable}} be findings remaining actionable.
A parser can satisfy S_{\mathrm{syn}} while failing the other three conditions.
Product identity failures can widen scope
Suppose a source assertion concerns component C_1 inside product P:
X:
(P,C_1,V)
\mapsto
\texttt{NOT\ AFFECTED}.
If conversion drops C_1, the target becomes:
X':
(P,V)
\mapsto
\texttt{NOT\ AFFECTED}.
If P also contains C_2 associated with the same vulnerability, X' can suppress more than the producer intended. This is scope widening. Safe conversion must preserve:
product identity;
version or artifact scope;
subcomponent scope;
vulnerability identity;
status;
justification;
timing and supersession semantics where operationally relevant.
Semantic loss can strengthen a claim
Consider CycloneDX protected_at_perimeter and CISA/OpenVEX inline_mitigations_already_exist. A perimeter control is not necessarily a product-integrated mitigation. Mapping one to the other can strengthen the claim rather than merely remove detail.
A safe conversion must not make the target assertion semantically stronger than the source assertion. If equivalent or weaker semantics cannot be established, the converter should label the mapping as lossy or unsupported rather than invent a stronger target justification.
Trust has several independent layers
The consumer predicate in Equation 15 can be decomposed operationally into six independent trust dimensions:
authentication of the issuer;
authorization of that issuer for the relevant product scope;
identity applicability for both product and vulnerability;
freshness of the assertion and its assumptions;
semantic and scope preservation across representation or conversion;
local policy acceptance by the consumer.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart TD
X[VEX assertion]
S{Format valid?}
A{Issuer<br/>authenticated?}
Z{Issuer<br/>authorized?}
I{Product + vulnerability<br/>match?}
F{Fresh?}
M{Meaning + scope<br/>preserved?}
P{Local policy<br/>accepts?}
D[Accepted VEX<br/>may influence finding disposition]
R[Do not apply VEX<br/>continue handling]
X --> S
S -->|Yes| A
A -->|Yes| Z
Z -->|Yes| I
I -->|Yes| F
F -->|Yes| M
M -->|Yes| P
P -->|Yes| D
S -->|No| R
A -->|No| R
Z -->|No| R
I -->|No| R
F -->|No| R
M -->|No| R
P -->|No| R
Figure 10: A VEX assertion should pass independent format, authentication, authorization, identity, freshness, semantic, and local-policy gates before it can influence a finding disposition.
Authentication and authorization are different. A valid signature from an upstream library maintainer does not automatically make that maintainer authoritative about a downstream modified appliance.
Freshness is about assumptions
Let \Gamma_X be the set of assumptions on which assertion X depends. A useful semantic definition is
These are not necessarily contradictory. The distributor may have backported a patch, and the final product may omit the relevant package. Conflict exists only when statements refer to materially equivalent product scope:
The latter states describe why the consumer cannot safely accept a conclusion.
Failure-mode taxonomy
Failure
Layer
Consequence
Unsupported VEX syntax
Syntax
Statement ignored
Wrong product match
Identity
Statement applied to wrong artifact
Subcomponent scope discarded
Identity/semantics
Suppression widened
false_positive normalized to generic not-affected
Semantics
Association error loses its meaning
Stronger target justification invented
Semantics
Converted claim exceeds source evidence
Product changed after assessment
Freshness
Previously valid assertion becomes stale
Unauthenticated VEX accepted
Authentication
Unauthorized suppression possible
Authenticated but unauthorized issuer accepted
Authorization
Wrong party controls downstream disposition
Conflict resolved by timestamp alone
Policy
Lower-authority assertion can override better evidence
Incomplete SBOM treated as proof of absence
Evidence
Correlated false negative
Suppressed finding deleted
Auditability
Decision cannot be reconstructed
Table 9: Major VEX failure modes.
The highest-risk failure occurs when a real vulnerability is paired with an incorrectly accepted NOT AFFECTED assertion and automation turns that incorrect assessment into a false negative.
The final consumer rule is therefore simple: a VEX assertion may change or suppress a finding only after it satisfies the acceptance conditions in Equation 15, and the original finding plus the acceptance decision must remain recoverable.
How the Cyber Resilience Act leverages SBOM and VEX in practice
The Cyber Resilience Act provides a regulatory context in which the difference between SBOM and VEX becomes operationally important. Regulation (EU) 2024/2847 requires manufacturers subject to its full vulnerability-handling regime to identify and document vulnerabilities and components and to create an SBOM in a commonly used, machine-readable format covering at least the product’s top-level software dependencies.33
The CRA does not prescribe VEX as a mandatory artefact and does not require one particular VEX serialization. The distinction is direct: the CRA requires an SBOM capability as part of the vulnerability-handling regime, whereas VEX is not itself a mandated CRA artefact. VEX can nevertheless support the manufacturer’s vulnerability decisions by communicating a scoped technical assessment. This distinction is consistent with the broader CRA analysis that treats an SBOM as a required inventory rather than a security verdict.34
The SBOM sits inside the vulnerability-handling process
The CRA’s SBOM requirement is part of Annex I, Part II, on vulnerability handling. It belongs to a larger lifecycle that includes identifying and documenting vulnerabilities, addressing vulnerabilities in relation to product risk, performing testing and review, making security updates available, and providing information about fixed vulnerabilities.35
Operationally, the SBOM sits upstream of vulnerability identification and product-specific assessment. The assessment can then drive remediation and the preservation of documented evidence. VEX fits naturally at the communication boundary after the technical assessment, rather than replacing any of those lifecycle stages.
11 September 2026 is not the general SBOM deadline
The CRA’s dates must be separated carefully. The Regulation applies generally from 11 December 2027.
Article 14 reporting obligations apply earlier, from 11 September 2026.36 The European Commission’s current implementation material confirms that from that date manufacturers must report actively exploited vulnerabilities and severe security incidents under the Article 14 regime, with progressive 24-hour, 72-hour, and final-report stages.37
The two dates therefore have different meanings: 11 September 2026 is the start of the Article 14 reporting regime, not a universal CRA SBOM-compliance deadline. The full Annex I regime applies later according to the Regulation’s transition provisions.
Nevertheless, SBOMs, scanners, VEX, telemetry, and case-management systems can already support the Article 14 decision process. This is the practical distinction developed in the companion analysis of CRA vulnerability scanning and reporting readiness.38
The SBOM answers the product-containment question
Article 14’s vulnerability route concerns an actively exploited vulnerability contained in the product with digital elements that the manufacturer becomes aware of.39
The first technical question is therefore whether vulnerability V is actually contained in product P. The SBOM helps answer whether a component associated with V is part of that product state.
For Log4Shell, knowing that a product contains log4j-api is not equivalent to establishing that vulnerable log4j-core is present. The SBOM reduces the search space. It does not decide legal reportability.
VEX answers the product-impact question
Once a component-vulnerability association exists, VEX can communicate the product-specific result already formalized in Equation 7: for the identified pair (P,V), the assessment provides status together with any applicable justification, impact information, and action information.
That can distinguish component matched from product affected or product not affected because vulnerable component is absent or assessment still under investigation. This is valuable CRA evidence, but the CRA reporting decision remains a separate proposition.
AFFECTED does not automatically mean Article 14 reporting
A simplified Article 14 vulnerability-route predicate can be written as
where the three predicates represent, respectively, CRA reporting scope, containment of vulnerability V in product P, and the manufacturer’s awareness at time t of active malicious exploitation.
A VEX AFFECTED statement can contribute evidence for \operatorname{Contained}(P,V) and product impact. It does not, by itself, establish \operatorname{AwareActiveExploitation}(P,V,t). That evidence may instead come from telemetry, customer reports, incident response, forensic artefacts, suppliers, authorities, or threat intelligence.
NOT AFFECTED can eliminate one vulnerability path, not every reporting path
Suppose a trusted assessment establishes NOT AFFECTED with justification component_not_present for the relevant product-vulnerability pair. If the vulnerable component is genuinely absent from the relevant product artifact, then the upstream component vulnerability is not contained in that product state. That can resolve the vulnerability route quickly. But Article 14 also includes a severe-security-incident route. A VEX conclusion about CVE V must not suppress investigation of an independent severe incident affecting the product.
UNDER INVESTIGATION is useful under the reporting clock
A new signal may establish only a possible component match while the product state and exploitation evidence remain incomplete. Recording UNDER INVESTIGATION is technically accurate in that situation.
Article 14’s progressive reporting structure, however, means that technical uncertainty cannot be used to postpone reporting after the legal awareness threshold has actually been reached.40
VEX describes technical knowledge. It does not stop statutory clocks.
The CRA evidence flow
The CRA reporting workflow should preserve the distinction between technical evidence, product-specific assessment, optional VEX communication, and the legal reporting decision. An SBOM and build evidence help establish what is contained in the product; technical assessment determines the product-specific significance of a vulnerability; VEX may communicate that assessment in a structured form; and exploitation or incident evidence addresses the separate question of whether an Article 14 reporting trigger has been reached. None of these artefacts or analyses should be treated as a substitute for the others.
%%{init: {"theme": "neo", "look": "handDrawn", "layout": "elk"}}%%
flowchart TD
S[Product-security signal]
P(Identify product<br/>and CRA scope)
B[SBOM + build evidence]
A(Technical product<br/>assessment)
V[VEX assertion<br/>optional communication artefact]
E[Telemetry + customer reports<br/>forensics + supplier evidence<br/>threat intelligence]
T{Actively exploited vulnerability<br/>contained in product?}
I{Severe security incident<br/>affecting product?}
D(Record awareness<br/>and reporting decision)
N(Progressive Article 14<br/>reporting workflow)
R(Vulnerability handling<br/>and reassessment)
S --> P
P --> A
B -. evidence .-> A
A --> V
A -. product-impact evidence .-> T
V -. optional communication of assessment .-> T
E -. exploitation evidence .-> T
E -. incident evidence .-> I
P -. scope context .-> T
P -. scope context .-> I
T -->|Yes| D
I -->|Yes| D
T -->|Not established| R
I -->|Not established| R
D --> N
R --> A
Figure 11: SBOM evidence, product-specific technical assessment, optional VEX communication, exploitation or incident evidence, and the CRA reporting decision remain distinct stages of the workflow.
Supplier vulnerability information remains product-specific
The CRA requires manufacturers to manage vulnerabilities affecting integrated components and to cooperate, where relevant, with the manufacturers or maintainers of those components when vulnerabilities are identified.41
An upstream component assessment and a downstream product assessment can therefore reach different conclusions without contradiction. For the same vulnerability V:
Library C / CVE-V: AFFECTED: the component itself is affected by the vulnerability.
Final Product P / CVE-V: NOT AFFECTED, with justification vulnerable_code_not_in_execute_path: the vulnerable component is present, but the vulnerable code is not reachable in the integrated product.
The two statements have different subjects and therefore make different claims. The upstream statement characterizes the vulnerability status of the component; the downstream statement characterizes the effect of that vulnerability on the specific integrated product.
Supplier information can support the downstream analysis, but it does not replace it. The final-product manufacturer must still establish the product-specific conditions needed to determine whether the vulnerability affects the product.
SBOM, VEX, and Article 14 evidence answer different questions
Evidence object
Primary question
Does not by itself establish
SBOM
What software is in the product?
Product exploitability or active exploitation
VEX
What is the assessed status of vulnerability V for product P?
Statutory Article 14 trigger
Exploitation / incident evidence
Is malicious exploitation or a severe security incident occurring?
Software composition
CRA case record
Has the legal reporting threshold been reached and what actions followed?
Complete conformity with all CRA requirements
Table 10: Distinct evidence roles in a CRA vulnerability workflow.
Operationally, those objects form a traceable evidence stack: the SBOM supports software-composition claims, VEX records product-specific vulnerability assessment, exploitation or incident evidence supports the statutory trigger analysis, and the CRA case record preserves the resulting decision and actions.
This is also the practical value of the two companion CRA analyses: they frame SBOM, vulnerability scanning, VEX, telemetry, and case management as inputs to an evidence-based lifecycle rather than as automatic legal verdicts.4243
Reportability and remediation remain separate
A vulnerability can require urgent remediation without meeting the Article 14 active-exploitation reporting trigger. Absence of an Article 14 reporting trigger therefore does not imply absence of vulnerability-management action.
The reverse distinction also matters: reporting a vulnerability does not replace remediation, user communication, technical documentation, or other CRA duties.
The regulatory roles are therefore distinct: the SBOM helps the manufacturer determine where relevant software is present; VEX communicates the product-specific conclusion reached by the technical assessment; and CRA governance determines what reporting, remediation, documentation, and communication obligations follow from the complete evidence record.
Practitioner playbook and conclusions
The central lesson is not that organisations need another vulnerability file format. They need a disciplined way to move from software composition to product-specific security conclusions without silently turning correlation into causation or automation into unaudited suppression.
The complete operational chain is the lifecycle already shown in Figure 3: the released software artifact is inventoried, candidate vulnerabilities are correlated, product-specific evidence is assessed, VEX communicates the resulting conclusion, consumers apply their own acceptance policy, and changed assumptions trigger reassessment.
Under the CRA, a separate governance layer consumes SBOM and VEX evidence together with exploitation or incident evidence and regulatory scope before a legal reporting or conformity decision is made.
These relationships should remain separate. An SBOM is evidence about what software is present.An SBOM provides evidence about software composition. VEX communicates the result of a product-specific vulnerability assessment. CRA reporting and conformity decisions apply legal criteria to a broader evidence record.
Choose the VEX implementation from the surrounding architecture
Implementation
Natural fit
Principal strength
Principal caution
CSAF 2.0
Vendor security advisories
Rich product/version, remediation, and advisory lifecycle semantics
Product-tree and advisory complexity
CycloneDX 1.7
Existing CycloneDX BOM pipelines
Reuse of BOM identities, dependencies, pedigree, and vulnerability objects
State and justification vocabularies are not isomorphic with CISA
SPDX 3.0.1
Graph-oriented supply-chain data
First-class assessment relationships and provenance
Requires graph-aware processing
OpenVEX 0.2.0
Lightweight feeds and attestations
Small model and close CISA mapping
Richer semantics can be lost; specification remains a draft
Table 11: Final practitioner selection guide.
The implementation choice should therefore be made from the surrounding architecture: the publisher’s role, the existing data model, the consumer ecosystem, the semantics that must survive interchange, and the intended distribution model all matter. There is no universally superior serializer.
Keep one canonical assessment outside the formats
For multi-format environments, maintain a canonical internal assessment record
A_c(P,V,t)=(s,j,i,a,E,\Gamma,\iota),
\tag{22}
where E is the supporting evidence, \Gamma the assessment assumptions, and \iota the issuer or approving authority. Serialize this richer record into CSAF, CycloneDX, SPDX, or OpenVEX rather than treating any one interchange format as the system of record.
This avoids forcing the internal security model to adopt the limitations of the least expressive interchange format.
Build capability in the least dangerous order
A defensible rollout is:
establish precise product and artifact identity;
generate artifact-relevant SBOMs;
correlate components with vulnerability intelligence;
when investigation begins, initialize the assessment as UNDER INVESTIGATION;
Here, \operatorname{NotAffectedBasisValid}(X) means that the assertion contains either an applicable structured justification or the impact statement required when no structured justification is provided. The additional evidence requirement is an internal assurance policy: syntactic compliance with the VEX format does not by itself establish that the not-affected claim is true.
If one of those conditions cannot be established, the safe outcome is continued vulnerability handling, not inferred safety.
Preserve the non-equivalences
Do not equate
With
Component present
Product affected
Scanner non-detection
Component proven absent
NOT AFFECTED
Risk accepted
NOT AFFECTED
Low severity
AFFECTED
Automatic emergency patch under every policy
FIXED for CVE V_1
Secure against every vulnerability
UNDER INVESTIGATION
Probably safe
Schema-valid VEX
Correct technical assessment
Signed VEX
Correct underlying assessment
Authenticated issuer
Authorized issuer for every product
Newer statement
More authoritative statement
Missing VEX
NOT AFFECTED
Successful conversion
Meaning preserved
Suppressed finding
Deleted finding
VEX AFFECTED
CRA Article 14 report automatically required
No Article 14 trigger
No remediation required
Table 12: Distinctions that a mature VEX and CRA workflow must preserve.
Use Log4Shell as an acceptance test
A mature VEX pipeline should be able to distinguish the four product states developed in the worked example:
Product state
Evidence condition
Expected VEX result
P_A
log4j-core absent from the assessed artifact
NOT AFFECTED with component_not_present
P_B
Vulnerable log4j-core present and the exploitability conditions are established
AFFECTED
P_C
A corrective release for CVE-2021-44228 has been incorporated
FIXED
P_U
Available evidence is still insufficient to determine product impact
UNDER INVESTIGATION
Table 13: Log4Shell states as an acceptance test for the VEX pipeline.
These four cases provide a useful acceptance test for the underlying assessment model. A system that can represent only a binary distinction between CVE found and CVE ignored still collapses vulnerability correlation and product-specific assessment into the same decision. In that case, adding VEX as an output format has not materially improved the security model.
Measure decision quality, not suppression volume
Useful programme measures include:
proportion of candidates with explicit assessed states;
percentage of NOT AFFECTED assertions linked to reviewable evidence;
percentage of statements bound to precise product identities;
time from vulnerability disclosure to UNDER INVESTIGATION;
time from completed investigation to updated VEX;
number of product-matching failures;
number of semantic-loss warnings during conversion;
stale assertions detected by reassessment;
suppressed findings reactivated after changed evidence or trust;
ability to reconstruct historical suppression decisions.
For CRA operations, also measure how quickly the organisation can establish product scope, exploitation or incident evidence, awareness time, and reporting disposition without confusing those values with the VEX status.
The target is decision quality—specifically correctness, traceability, and timeliness—not maximum suppression volume.
What VEX does, and does not do
VEX should be understood as a communication mechanism for product-specific vulnerability assessments, not as proof that every upstream analytical step was correct. A valid VEX statement does not establish that the underlying SBOM is complete, that component-to-vulnerability matching was accurate, that reachability analysis was sound, or that an asserted mitigation cannot be bypassed. Authentication can establish who issued the statement, but it does not make the issuer’s technical conclusion infallible.
The same boundary applies in the CRA context. An AFFECTED VEX status does not by itself establish active exploitation for Article 14 purposes, just as possession of an SBOM does not by itself establish conformity with the CRA’s broader vulnerability-handling requirements.
What VEX can do is narrower but still operationally important: it can communicate a scoped, attributable, machine-readable, and revisable assessment of what a specific vulnerability means for a specific product state.
Final conclusion
The enduring abstraction is a three-layer separation of concerns. The SBOM describes what software is present. VEX communicates what an assessed vulnerability means for the identified product. In the CRA context, regulatory governance determines what the manufacturer must do with the resulting evidence.
The maturity test for the complete system is straightforward. For every vulnerability whose operational treatment was changed by VEX, the organisation should be able to answer:
Which exact product was assessed, which vulnerability was considered, which component or code path was relevant, what evidence supported the status, which assumptions bounded the conclusion, who authorized the assertion, which VEX representation communicated it, which consumer policy accepted it, whether any regulatory decision depended on it, and what event would cause the assessment to be reconsidered?
If those questions cannot be answered, the primary problem is not the VEX standard that was selected. It is a missing reasoning chain.
The final safety invariant is operational rather than syntactic: any automated decision that changes a finding because of VEX should remain traceable to a reviewable assessment, be bound to precise product and vulnerability identities, rely on trusted provenance, and remain reversible if the assertion later becomes stale, inapplicable, or untrusted.
The CRA adds one further constraint: a regulatory decision must evaluate the applicable legal trigger independently of the VEX status. VEX may contribute evidence to that decision, but it must not substitute for it.
Under those constraints, SBOM and VEX become complementary elements of a defensible product-security system: the SBOM makes software composition inspectable, VEX makes product-specific vulnerability knowledge exchangeable, and the CRA gives manufacturers a concrete regulatory reason to ensure that both feed an evidence-driven security lifecycle rather than a purely scanner-driven one.
The main article compares VEX architectures at the semantic level. This appendix goes one level deeper for CycloneDX 1.7 because its VEX semantics are distributed across the ordinary BOM object model rather than encapsulated in a separate top-level VEX document type. Correct implementation therefore depends on understanding how document identity, product identity, vulnerability metadata, affects, version applicability, analysis, provenance, completeness, and trust controls interact.
This is an implementation and review reference, not a catalogue of every CycloneDX field. It focuses on fields that constitute, scope, qualify, transport, or materially support a VEX assertion, and it distinguishes three kinds of requirement throughout:
Schema requirement: enforced by the CycloneDX 1.7 serialization schema.
Specification semantics: meaning assigned to a field or enum by CycloneDX.
Operational policy: a stricter rule that a producer or consumer may impose for trustworthy VEX handling.
CycloneDX 1.7 is the stable BOM specification used in this appendix.44 Its VEX capability is expressed principally through vulnerabilities[].affects and vulnerabilities[].analysis, with supporting semantics elsewhere in the BOM.45
A map of the CycloneDX VEX surface
The most useful way to read the model is by semantic layer rather than by JSON-property order.
Layer
Principal fields
Question answered
Document identity and lifecycle
specVersion, serialNumber, root version, metadata
Which CycloneDX document and revision are being interpreted?
What did the producer conclude, why, and what response is intended?
Assessment lifecycle
analysis.firstIssued, analysis.lastUpdated
When was the assessment first issued and last updated?
Evidence and provenance support
proofOfConcept, tools, properties, signature
What supporting context, provenance, or integrity information accompanies the assertion?
Distribution and completeness
externalReferences, compositions
Is VEX maintained externally, and what completeness claims accompany the BOM?
Table 14: Semantic layers of the CycloneDX 1.7 VEX surface.
The central implementation principle is that these layers must not be collapsed. A vulnerability identifier is not a product identifier; version applicability is not the same thing as product-impact analysis; a signature is not proof of technical correctness; and a schema-valid document can still encode a weak or misleading security conclusion.
Document envelope: identify the document before interpreting the assertion
A minimal CycloneDX 1.7 JSON document can begin as follows:
The root JSON schema requires bomFormat and specVersion; fields such as serialNumber, root version, metadata, and vulnerabilities are available but are not all mandatory merely for structural validity.46
Field
Schema / model role
VEX implementation significance
$schema
JSON Schema locator
Useful to validation tooling. It does not identify the software product or the VEX assessment.
bomFormat
Format discriminator
Identifies the document as CycloneDX. It carries serialization semantics, not vulnerability semantics.
specVersion
CycloneDX specification version
Determines which field and enum semantics the consumer should apply.
serialNumber
BOM-instance lineage identifier
Identifies the BOM lineage, not the software product itself.
root version
BOM revision number
Identifies a revision of the BOM document; it must not be confused with product or component version.
metadata
Document context
Can identify the BOM subject, timestamp, authors/manufacturer, and tools used to create the BOM.
vulnerabilities
Vulnerability collection
Carries VDR/VEX-related vulnerability objects.
externalReferences
Links to external resources
Can identify separately maintained VEX through type = exploitability-statement.
compositions
Completeness assertions
Can express completeness of selected represented relationships or inventories.
signature
Cryptographic envelope
Can provide integrity and origin evidence, but not technical truth.
Table 15: CycloneDX document-level fields most relevant to VEX.
Root version is not product version
A common implementation error is to confuse the BOM’s root version with the version of the software being described. If the root contains version = 4, that means revision 4 of the BOM lineage. If metadata.component.version = "4.0.0", that means software product version 4.0.0.
A consumer that joins VEX to assets using the root BOM revision rather than the component or product version is matching the wrong identity domain.
Product identity: metadata.component, bom-ref, and stable identifiers
CycloneDX does not require every product-level VEX assertion to use metadata.component as its target. affects[].ref can point to an appropriate component or service elsewhere in the BOM. Nevertheless, metadata.component is a natural way to identify the subject when the BOM itself represents a product-level assessment, and it appears in CycloneDX’s official VEX examples.47
For VEX purposes, the following component fields are particularly important:
Field
Technical meaning for VEX
bom-ref
Referential identity used to join objects within a BOM or through BOM-Link.
type
Distinguishes semantic kinds such as application, library, container, firmware, or other component classes.
manufacturer / supplier
Organisational identity useful for disambiguation and provenance.
group
Namespace or grouping identifier, particularly useful in package ecosystems.
name
Human-readable name; usually too weak by itself for automated applicability decisions.
version
Product or component version; important but not always sufficient where patches are backported or builds are repackaged.
purl
Package URL; often a strong package-level identifier.
cpe
CPE product identifier; useful where vulnerability intelligence is CPE-oriented.
hashes
Byte-level integrity identifiers; strong for exact artifact binding.
pedigree
Modification and ancestry information; especially relevant to resolved_with_pedigree.
Table 16: Component identity fields that materially affect VEX applicability.
bom-ref is referential identity, not necessarily global identity
A vulnerability object can later refer to that component through:
{"affects":[{"ref":"billing-app"}]}
The second object refers back to the first. This establishes referential resolution inside the CycloneDX model; it does not establish that the string billing-app is globally unique or sufficient to match a consumer’s deployed asset.
A consumer receiving separately distributed VEX still needs enough stable identity information, such as PURL, CPE, version, hashes, BOM-Link context, or another governed identifier, to establish that the assertion applies to the local software object. This is the same identity principle developed in the main article: a VEX consumer must match the same product state, not merely a similar display name.
Vulnerability objects: identity, source, context, and evidence
At the root of a CycloneDX document, vulnerability information is carried in the vulnerabilities array:
{"vulnerabilities":[{"...":"..."}]}
CycloneDX is deliberately broader than VEX. A vulnerability object can carry identifiers, severity and risk ratings, source descriptions, advisories, reproduction material, timestamps, remediation guidance, product-specific analysis, applicability information, and extension properties.48
The practical consequence is that upstream vulnerability facts and downstream product-specific assessment coexist in the same object. Producers and consumers must preserve the boundary between them.
Vulnerability bom-ref and vulnerability id are different
vulnerability bom-ref: a CycloneDX referential identifier for this vulnerability object;
vulnerability id: the externally meaningful vulnerability identifier.
Use bom-ref when another CycloneDX object must refer to the vulnerability object. Use id to state which vulnerability the object represents.
Interpret id together with source
CycloneDX does not restrict vulnerability identifiers to CVE. Other identifiers can appear, including GHSA or source-specific identifiers.49 For high-assurance automation, the conceptual identity should therefore be treated as the pair (id, source) rather than as id interpreted in isolation.
identifies the source of the vulnerability information. It does not necessarily identify the organisation that performed the downstream product-impact assessment. A document can therefore coherently represent an NVD vulnerability record while the product-impact assessment is produced by an entirely different product-security team. The vulnerability source and the VEX assessor are separate roles.
references and advisories should not be conflated
vulnerabilities[].references is intended for references to equivalent vulnerability records or identifiers in other sources. A CVE record, for example, can point to a corresponding GHSA record. A published security advisory instead belongs under advisories, not under references merely because it has a URL.
For automated correlation, the distinction is:
references: identity and correlation across vulnerability-information sources;
advisories: security publications relevant to the vulnerability.
Vulnerability-context fields
Several fields materially support vulnerability analysis without themselves constituting VEX conclusions:
Temporary bypass or operational change that reduces likelihood or impact
not_affected
proofOfConcept
Reproduction steps, environment, and supporting material
Applicability to every product embedding the component
advisories
Published advisory material
Product identity
created, published, updated, rejected
Lifecycle of the vulnerability record
Lifecycle of the product-specific VEX assessment
credits
Parties credited with vulnerability discovery
Authority to issue product-specific VEX
tools
Tools used to identify, confirm, or score the vulnerability
Correctness of the assessment
Table 17: Vulnerability-context fields that support, but do not replace, product-specific VEX analysis.
Severity is not exploitability
A CVSS or other rating can support prioritisation, but it does not answer whether a vulnerability affects a specific product state. A critical upstream vulnerability can be not_affected for one product because its exploitability preconditions fail; conversely, a lower-severity vulnerability can still be exploitable. ratings should therefore influence prioritisation policy, not replace analysis.
description and vulnerability-level detail are source-oriented
A useful discipline is to keep description and vulnerability-level detail for upstream vulnerability facts, while analysis.detail carries the downstream product-specific assessment.
For example, a statement such as the upstream vulnerability permits X under conditions Y belongs in vulnerability-level description or detail. A statement such as this product is not affected because the vulnerable path is unreachable belongs in analysis.detail.
Mixing these roles makes it difficult for consumers to distinguish information inherited from vulnerability intelligence from reasoning produced by the product-security assessor.
Recommendation and workaround are not status fields
Recommendation, workaround, and analysis state are independent dimensions. The following combinations are coherent:
analysis.state = exploitable with recommendation = upgrade;
analysis.state = not_affected with a recommendation to upgrade later for another operational reason;
analysis.state = exploitable while a workaround is available.
The presence of a recommendation or workaround therefore does not by itself alter the VEX status.
Vulnerability timestamps and VEX timestamps are different
CycloneDX vulnerability objects can contain created, published, updated, and rejected; these belong to the lifecycle of the vulnerability record. By contrast, analysis.firstIssued and analysis.lastUpdated belong to the product-specific impact analysis.
A CVE can therefore be published at time t_0 and a product-specific assessment first issued later at time t_1. That is expected and should not be normalized into a single timestamp.
rejected is not false_positive
A rejected vulnerability record means the vulnerability-information process has rejected that record. analysis.state = false_positive, by contrast, means the vulnerability was falsely identified or associated with the referenced component or service in the assessed context.
A valid CVE can therefore still be a false-positive match for one component. The two concepts belong to different semantic layers.
affects: scope the vulnerability to the referenced object
The affects structure connects vulnerability information to components or services. For example:
Each affects item requires ref in the CycloneDX 1.7 JSON model.50 This is a critical structural requirement because analysis without resolvable applicability can leave the consumer unable to determine which component or service the analysis is about.
affects[].ref
ref identifies the target component or service through CycloneDX referential identity, normally by a bom-ref or an appropriate BOM-Link element reference.
A safe consumer should:
resolve affects[].ref;
establish the referenced component or service identity;
determine whether a version constraint applies;
only then interpret analysis for that target scope.
If the reference cannot be resolved, the consumer should not infer applicability merely from the presence of analysis.
affects[].versions
versions narrows applicability beneath the referenced component or service. Each version object selects either a single version or a range and can associate the selected scope with an applicability status. A producer should not treat version and range as independent selectors for the same item.
A single version can be expressed as:
{"version":"4.2.0","status":"unaffected"}
The version value is intentionally flexible, so consumers must not assume semantic-version ordering unless the relevant ecosystem actually follows SemVer.
CycloneDX 1.7 uses Package URL Version Range (vers) syntax for ranges.51 For example:
The ecosystem is part of the semantics. Version ordering rules differ across ecosystems, so consumers should use a vers-aware parser rather than generic string comparison or an assumed SemVer implementation.
affects[].versions[].status
The applicability enum consists of affected, unaffected, and unknown. CycloneDX defines the status as affected by default when the field is omitted.52
For an explicitly unaffected range, producers should write "status": "unaffected" rather than relying on omission. This field answers a version-applicability question and should not be conflated with the broader product-impact state in analysis.state.
affects[].versions[].status is not analysis.state
These fields are related but distinct:
affects[].versions[].status asks whether vulnerability V applies to a version or version range of the referenced object;
analysis.state asks for the current product/component impact-analysis conclusion in the assessed context.
A producer should keep the two semantically coherent, but a consumer should not derive one mechanically from the other.
WarningInteroperability note: the official JSON and XML VEX examples currently diverge
As checked on 22 August 2026, the CycloneDX Vulnerability Exploitability use-case page presents an otherwise corresponding JSON and XML example with different analysis.state values. The JSON example uses analysis.state = not_affected, while the XML example uses analysis.state = exploitable; both mark the illustrated version range as unaffected.
The page’s explanatory text describes the application as not affected. Implementations should therefore validate JSON/XML conversion against independently defined expected semantics rather than assuming that illustrative examples are mutually equivalent.53
analysis: the core product-impact assessment
The analysis object is the centre of CycloneDX VEX semantics. A typical object can contain:
{"analysis":{"state":"not_affected","justification":"code_not_reachable","response":["update"],"detail":"The vulnerable function is not reachable from any supported application path.","firstIssued":"2026-08-20T09:00:00Z","lastUpdated":"2026-08-21T10:00:00Z"}}
CycloneDX’s general BOM model is permissive. Structural validation alone does not amount to a VEX quality policy, so an operational producer profile should normally impose stronger requirements where necessary.
At minimum, a useful product-impact assertion normally needs:
a resolvable target through affects;
a vulnerability identity;
an analysis.state;
enough explanation and provenance to support the state.
For not_affected, a producer should provide a semantically appropriate justification where available and meaningful detail explaining the actual product-specific basis.
analysis.state
CycloneDX 1.7 defines six analysis states:
State
Meaning in the CycloneDX model
Closest CISA concept
Important caveat
resolved
Vulnerability has been remediated in the assessed context
FIXED
Product/component scoped
resolved_with_pedigree
Remediated, with corrective provenance represented through pedigree
FIXED with stronger provenance
Requires meaningful pedigree information
exploitable
Directly or indirectly exploitable in the assessed context
AFFECTED
Does not mean actively exploited in the wild
in_triage
Under investigation
UNDER INVESTIGATION
Investigation is active; uncertainty is not safety
false_positive
Vulnerability incorrectly identified or associated with the target
No exact CISA core state
Matching-error semantics
not_affected
Referenced component or service is not affected
NOT AFFECTED
Basis should be explained
Table 18: CycloneDX 1.7 analysis states and their VEX interpretation.
resolved
resolved means that the vulnerability has been remediated for the referenced component or service context. It is scoped to the represented object and product state; it does not mean that the vulnerability has disappeared globally.
resolved_with_pedigree
resolved_with_pedigree adds structured change provenance to the remediation conclusion. A producer should not use this state merely because it knows the name of a fixed upstream release. The value is meaningful when CycloneDX pedigree represents the corrective change, such as ancestry, patches, commits, or diffs associated with the assessed component.
exploitable
CycloneDX describes this state as directly or indirectly exploitable.54 It is the closest CycloneDX analogue to CISA AFFECTED, but exploitable does not mean actively exploited in the wild.
The former is a product-impact conclusion; the latter requires exploitation or incident evidence. This distinction is particularly important when CycloneDX VEX is used as evidence in a CRA Article 14 workflow.
in_triage
in_triage means that the vulnerability is being investigated. Use it when an assessment is underway but the available evidence is not yet sufficient to support a final product-impact conclusion. Do not encode unresolved uncertainty as not_affected.
false_positive
false_positive describes a matching or association error: the vulnerability is not specific to the referenced component or service and was incorrectly identified or associated.
The distinction is:
false_positive: the association itself is wrong;
not_affected: the vulnerability is valid, but the assessed target is not impacted in the asserted context.
not_affected
not_affected states that the referenced component or service is not affected. The specification encourages the producer to provide justification and detailed explanation for non-exploitable cases.55
An unexplained analysis.state = not_affected may be structurally accepted, but it tells the consumer neither why the target is not affected nor what assumptions and evidence support the claim. A production profile should therefore treat unexplained not_affected conclusions as weak.
analysis.justification: nine different reasons, not one Boolean
CycloneDX 1.7 defines nine justification values:
code_not_present;
code_not_reachable;
requires_configuration;
requires_dependency;
requires_environment;
protected_by_compiler;
protected_at_runtime;
protected_at_perimeter;
protected_by_mitigating_control.
These values are broader than the five CISA NOT AFFECTED justifications and should not be mapped by lexical similarity alone.
Justification
Meaning
Operational implication
Interoperability caution
code_not_present
Vulnerable code has been removed or tree-shaken
Bind the claim to the actual built artifact
Not equivalent to CISA component_not_present
code_not_reachable
Vulnerable code is not invoked at runtime
Reachability assumptions and coverage matter
Close to vulnerable_code_not_in_execute_path
requires_configuration
Exploitation depends on a configuration state that is not present
Configuration becomes an assessment assumption
Reassess if configuration changes
requires_dependency
Exploitation depends on another dependency that is absent
Absence concerns an exploit prerequisite
Not necessarily component_not_present
requires_environment
Exploitation depends on an absent environmental condition
Build configuration and binary properties are evidence
Bind to the actual build
protected_at_runtime
Runtime protection prevents exploitation
Runtime control must remain present and effective
Reassess if runtime policy changes
protected_at_perimeter
Perimeter protection prevents the relevant attack path
Conclusion may depend on external architecture
Not equivalent to an inline product mitigation
protected_by_mitigating_control
A mitigating control protects against exploitation in the assessed context
Identify the actual control and its assumptions
Target formats may encode mitigation semantics differently
Table 19: CycloneDX 1.7 justification semantics and interoperability cautions.
code_not_present
code_not_present refers to vulnerable code, not necessarily to the whole component. A component identity can remain present while the vulnerable code has been removed, patched out, or tree-shaken. This is why mapping it to CISA component_not_present is unsafe.
code_not_reachable
code_not_reachable means vulnerable code exists but is not invoked through the relevant runtime paths. The statement is only as strong as the reachability analysis supporting it, so relevant coverage assumptions should be preserved in analysis.detail or in the internal assessment record.
requires_configuration
The conclusion depends on a configuration state that is absent. Examples include a feature that must be enabled, a parser mode that must be selected, a protocol option that must be configured, or a security-sensitive environment variable. Because configuration becomes part of the assessment’s assumption set, a configuration change can invalidate the VEX assertion even when the software artifact itself does not change.
requires_dependency
The vulnerable component may be present while an additional dependency required for exploitation is absent. This is not the same claim as saying that the vulnerable component itself is absent.
requires_environment
Environmental prerequisites can include operating-system capabilities, runtime features, hardware properties, or deployment characteristics. Because the conclusion depends on environmental state rather than only on immutable artifact composition, it may require more frequent reassessment.
protected_by_compiler
A compiler-based protection should be tied to the actual built artifact. Supporting evidence can include compiler flags, generated guards, hardening transformations, binary inspection, and reproducible build provenance. The source tree alone is insufficient if the assertion depends on build-time protections.
protected_at_runtime
Runtime protection is stronger than saying exploitation has not been observed. A defensible assessment should state which runtime control prevents exploitation, whether that control is mandatory, and under which configurations the claim remains valid.
protected_at_perimeter
Perimeter protection can depend on a network boundary, gateway, filter, WAF, physical boundary, or another external control. This is one of the clearest places where CycloneDX can express semantics that do not map directly to CISA’s inline_mitigations_already_exist. A converter must not strengthen an environmental or architectural protection into a claim about an intrinsic product mitigation.
protected_by_mitigating_control
This value indicates that a mitigating control protects against exploitation in the asserted context.56 The important implementation question is not the label alone but the control that makes the conclusion true. analysis.detail should identify the relevant mechanism, scope, and assumptions.
analysis.response: what the responsible party intends to do
response is an array and can contain more than one value. CycloneDX 1.7 defines can_not_fix, will_not_fix, update, rollback, and workaround_available. Responses are particularly useful when analysis.state = exploitable; the CycloneDX reference strongly encourages responses for exploitable vulnerabilities.57
Response
Meaning
VEX interpretation
can_not_fix
Responsible party cannot provide a fix
Operational disposition; does not make the vulnerability non-exploitable
will_not_fix
Responsible party does not plan to fix
Policy/disposition decision
update
Update to another revision or release
Natural response for upgrade remediation
rollback
Revert to an earlier revision or release
Useful when a newer release introduced the vulnerable condition
workaround_available
A workaround exists
Does not itself change exploitability state
Table 20: CycloneDX 1.7 vulnerability responses.
For example, state = exploitable together with response = can_not_fix is coherent: can_not_fix is a response to an affected condition, not a reason to rewrite that condition as not_affected.
analysis.detail: where product-specific reasoning becomes reviewable
analysis.detail should explain the assessment rather than merely repeat its state. A useful detail normally includes the technical mechanism relevant to the conclusion, the exact product or deployment scope, important assumptions, a concise evidence summary, and relevant reassessment triggers.
For example:
{"detail":"Static call-graph analysis of the released binary and integration testing show no supported execution path from external inputs to the vulnerable parser."}
is materially stronger than:
{"detail":"Not vulnerable."}
The second statement adds almost no information beyond analysis.state. The external VEX statement does not need to carry the complete internal evidence package, but analysis.detail should preserve enough reasoning for a consumer to understand the basis and scope of the claim.
analysis.firstIssued and analysis.lastUpdated
firstIssued records when the impact analysis was first issued, while lastUpdated records the most recent update to that analysis. Operationally:
firstIssued should remain stable for the same assessment lineage;
lastUpdated should change when the assessment itself is revised;
neither timestamp can compensate for incorrect product identity or stale assumptions.
Freshness is therefore semantic, not merely chronological. A recently updated statement can still be inapplicable to the local product, while an older statement can remain correct for an immutable artifact if its assumptions still hold.
proofOfConcept, tools, and supporting provenance
CycloneDX can carry reproduction evidence through proofOfConcept, including reproduction steps, environment, and supporting material.58 For example:
This is vulnerability evidence, not automatically product-specific VEX evidence. A PoC proving that vulnerability V is exploitable in one environment does not establish that every product embedding the component is affected.
Likewise, tools can identify scanners, reachability analyzers, static-analysis tools, or internal vulnerability services that participated in identifying, confirming, or scoring the vulnerability. Tool identity provides provenance; it does not prove that the assessment result is correct.
properties: extend metadata without redefining core semantics
CycloneDX properties can carry extension metadata such as an internal assessment identifier:
Useful applications include internal assessment IDs, evidence-system references, workflow metadata, policy identifiers, and extension data. Properties should not be used to contradict or replace core semantics. For example, a document should not state analysis.state = not_affected while a private property such as example:real-state says affected. A consumer should not need a private property namespace to discover that the core VEX field means something different from what it says.
External VEX through externalReferences
CycloneDX can keep the SBOM lifecycle and VEX lifecycle separate. An external reference can identify a VEX resource using:
CycloneDX 1.7 defines exploitability-statement specifically for a VEX resource.59
Field
Technical role
type
Describes the external resource; exploitability-statement identifies VEX
url
URI or BOM-Link locating the external resource
comment
Human-readable context
hashes
Integrity values where available
properties
Extension metadata
Table 21: External-reference fields relevant to separately maintained VEX.
This architecture is useful when software composition remains unchanged while vulnerability knowledge changes more frequently. Discovery still does not imply trust: the consumer must separately verify source authenticity, issuer authority, product applicability, freshness, and local acceptance policy.
compositions: completeness is not vulnerability status
compositions communicates completeness of represented relationships or inventories. It does not state whether a particular vulnerability affects a product.
Aggregate values include complete, incomplete, incomplete_first_party_only, incomplete_third_party_only, unknown, and not_specified, with additional specialised first-party/third-party proprietary/open-source forms in the model.60
A composition marked complete can increase confidence that the producer is making an intentional completeness claim about the referenced relationship set. It does not prove that every vulnerability assessment is technically correct.
As checked on 22 August 2026, the CycloneDX Vulnerability Compositions use-case example places the application’s bom-ref in compositions[].vulnerabilities while the vulnerabilities array itself is empty. The 1.7 schema/reference describes the composition’s vulnerability references in terms of vulnerability bom-ref identifiers.
Those materials are not obviously aligned. Implementations should therefore drive validation from the normative schema/model and cover the intended composition semantics with interoperability tests rather than inferring production behaviour solely from the illustrative use-case page.61
signature: authenticity is not correctness
CycloneDX supports a BOM-level signature structure.62 For VEX, cryptographic verification can support integrity, origin authentication, and binding to a signing identity depending on the signature and trust model. It does not establish that the product-security conclusion is technically true.
A correctly signed analysis.state = not_affected can still be wrong because the evidence was incomplete, the issuer was not authoritative for the target product, the product identity was mismatched, or the assessment assumptions no longer hold. Cryptographic verification and evidence validation are therefore separate controls.
From permissive schema to a strict VEX producer profile
The field commentary above describes what CycloneDX can represent. Production use requires a second question: what should an organisation require before it accepts a CycloneDX document as operational VEX?
A VEX-specific producer profile can be deliberately stricter than the base CycloneDX schema. A defensible profile might require:
This is not a replacement schema for CycloneDX. It is a local semantic-quality profile layered on top of CycloneDX conformance. Schema conformance asks whether the document is structurally valid; operational acceptance asks whether the assertion is sufficiently identified, scoped, supported, attributable, and current to influence vulnerability handling.
Recommended state-specific producer rules
A practical producer profile can add state-specific rules:
analysis.state
Recommended producer rule
in_triage
Identify the target and vulnerability; state that assessment is active; do not imply safety
exploitable
Provide response/action information and product-impact detail
not_affected
Provide an appropriate justification where available, detailed reasoning, assumptions, and evidence linkage
false_positive
Explain why the vulnerability/component association is incorrect
resolved
Identify the corrective product state or remediation
resolved_with_pedigree
Ensure pedigree actually carries the corrective provenance implied by the state
Table 22: Example state-specific producer policy layered on CycloneDX 1.7.
Annotated minimal not_affected example
The following example uses ordinary CycloneDX 1.7 fields and deliberately makes product identity, applicability, analysis state, justification, and assessment lifecycle explicit.
{"$schema":"https://cyclonedx.org/schema/bom-1.7.schema.json","bomFormat":"CycloneDX","specVersion":"1.7","serialNumber":"urn:uuid:8c7ab3bb-6a70-4b89-8b11-a3c3926195ad","version":1,"metadata":{"timestamp":"2026-08-22T00:30:00+02:00","component":{"bom-ref":"example-app-4.2.0","type":"application","name":"Example App","version":"4.2.0","purl":"pkg:generic/example-app@4.2.0"}},"vulnerabilities":[{"bom-ref":"vulnerability-cve-yyyy-nnnn","id":"CVE-YYYY-NNNN","source":{"name":"Example Vulnerability Authority"},"analysis":{"state":"not_affected","justification":"code_not_reachable","detail":"Static call-graph analysis of the released artifact and integration testing show no supported execution path from an external product interface to the vulnerable function. The conclusion applies to Example App 4.2.0 as identified by the referenced product object and must be reassessed if routing, feature configuration, or the packaged dependency graph changes.","firstIssued":"2026-08-20T09:00:00Z","lastUpdated":"2026-08-21T11:00:00Z"},"affects":[{"ref":"example-app-4.2.0","versions":[{"version":"4.2.0","status":"unaffected"}]}]}]}
Read semantically, the document says:
Document semantics: interpret the document as CycloneDX 1.7.
Product subject: Example App version 4.2.0, referenced as example-app-4.2.0.
Vulnerability: CVE-YYYY-NNNN.
Version applicability: version 4.2.0 is marked unaffected.
Analysis state: not_affected.
Structured reason: code_not_reachable.
Scope of reasoning: no supported path from an external product interface reaches the vulnerable function under the stated artifact and configuration assumptions.
Assessment lifecycle: first issued on 20 August 2026 and updated on 21 August 2026.
It does not claim that the vulnerable dependency is absent, that the CVE is low severity, that exploitation has never occurred anywhere, that every deployment configuration is unaffected, or that every future build of Example App will remain unaffected. Nor does it claim that the conclusion remains valid after relevant routing, feature, dependency, or configuration changes.
That is the practical value of keeping identity, applicability, analysis state, justification, assumptions, and time separate.
Consumer-side interpretation checklist
A CycloneDX VEX consumer can review a document in the following order:
Question
Field(s) that should answer it
Which CycloneDX semantics apply?
specVersion
Which BOM lineage and revision is this?
serialNumber, root version
Which product or component is being assessed?
metadata.component or referenced component/service identity
How is that object referenced?
bom-ref / BOM-Link
Which stable external identifiers are available?
purl, cpe, version, hashes, governed identifiers
Which vulnerability is being discussed?
vulnerabilities[].id, source, references
What upstream severity/risk information exists?
ratings
What is the upstream vulnerability mechanism?
description, vulnerability-level detail, cwes
Which product/component does the assertion concern?
affects[].ref
Which versions are covered?
affects[].versions[].version / range
What is their applicability?
affects[].versions[].status
What is the product-impact conclusion?
analysis.state
Why was that conclusion reached?
analysis.justification, analysis.detail
What response is intended?
analysis.response, recommendation, workaround
When was the assessment first issued?
analysis.firstIssued
When was it last updated?
analysis.lastUpdated
When was the vulnerability record itself published or changed?
created, published, updated, rejected
Is reproduction evidence available?
proofOfConcept
Which tools contributed?
tools
Is a completeness claim present?
compositions
Is VEX maintained externally?
externalReferences[type=exploitability-statement]
Is integrity/authentication information present?
signature and surrounding trust mechanism
Is the technical conclusion actually trustworthy?
Not answerable from schema fields alone: evaluate evidence, issuer authority, applicability, freshness, and local policy
Table 23: Field-by-field interpretation order for a CycloneDX 1.7 VEX consumer.
What schema validation can and cannot establish
CycloneDX gives producers and consumers a rich machine-readable vocabulary for vulnerability context, applicability, product-impact analysis, response, provenance, and distribution. That does not make the represented security judgment true merely because the document validates.
For a not_affected assertion to influence vulnerability disposition safely, a consumer should normally establish all of the following:
Schema conformance: the document is valid for the expected CycloneDX version.
Semantic coherence: affects, version applicability, analysis.state, justification, and detail do not contradict one another.
Product applicability: the assertion matches the actual local product/component and relevant version or artifact state.
Vulnerability applicability: the correct vulnerability identity is being interpreted.
Issuer authentication and authority: the source is authenticated and authorised for the asserted product scope.
Freshness: assumptions underlying the assessment still hold.
Evidence support: the technical basis is sufficient for the asserted conclusion.
Local-policy acceptance: the consumer’s own policy permits the assertion to change vulnerability disposition.
The final distinction is therefore not between valid CycloneDX and invalid CycloneDX. It is between serialization validity and defensible security use.
A CycloneDX document can be perfectly valid and still be unsafe to use for automated suppression. Conversely, a well-governed CycloneDX VEX pipeline can use the standard’s identity, applicability, analysis, lifecycle, and provenance fields to carry a precise product-specific conclusion while keeping the richer evidence package and approval record in the producer’s internal assessment system.
That is the appropriate role of CycloneDX VEX in the architecture developed in this article: a structured projection of a product-specific vulnerability assessment, not a substitute for the assessment itself.
Appendix: CSAF 2.0 VEX implementation reference
The main article treats VEX as a product-specific vulnerability assessment that must preserve product identity, vulnerability identity, scope, status, justification, action information, provenance, and lifecycle. CSAF 2.0 expresses those semantics inside a much broader security-advisory language. Unlike CycloneDX, where VEX information is embedded in a Bill-of-Materials model, CSAF defines a dedicated VEX profile that constrains how the general advisory vocabulary must be used.63
That architectural difference matters. A CSAF document can be valid against the general CSAF JSON Schema without satisfying the VEX profile, and a document can satisfy the VEX profile while still being unsafe for a particular consumer to trust or automate. This appendix therefore distinguishes three levels throughout:
Schema validity: the JSON instance conforms to the CSAF 2.0 schema.
CSAF VEX profile conformance: the document also satisfies the profile-specific rules and mandatory semantic tests defined by CSAF 2.0.
Operational acceptance: a consumer has established that the issuer, product identity, vulnerability identity, scope, freshness, and supporting assessment are trustworthy enough for the intended vulnerability-management action.
The normative baseline used here is the OASIS Standard Common Security Advisory Framework Version 2.0, published on 18 November 2022, together with its normative JSON Schema.6465 OASIS Approved Errata 01, published on 26 January 2024, did not change the CSAF document or CSAF JSON schema; its substantive correction affected the separate aggregator schema.66
NoteCSAF 2.1 is not the normative baseline of this appendix
As checked on 22 August 2026, CSAF 2.1 is at Committee Specification Draft 02, dated 25 February 2026. It is an active standards-track revision, but it has not replaced CSAF 2.0 as the OASIS Standard baseline used here.67
This appendix therefore describes CSAF 2.0 semantics. Implementers evaluating CSAF 2.1 should perform an explicit migration review rather than assuming that every 2.0 field, validation rule, profile requirement, or interoperability assumption remains unchanged.
A map of the CSAF VEX surface
The most useful way to read CSAF VEX is by semantic layer rather than by the physical order of properties in the JSON document.
May this document safely alter local vulnerability disposition?
Table 24: Semantic layers of a CSAF 2.0 VEX document.
The central implementation principle is that these layers are connected but not interchangeable. A Product ID is not a globally meaningful asset identifier, a known_not_affected status is not complete without the required product-scoped impact statement, a remediation is not itself a vulnerability status, and a correctly structured advisory does not prove that the underlying security assessment is true.
The CSAF VEX profile: more than schema-valid JSON
CSAF deliberately uses profiles because the general language supports several advisory use cases and therefore leaves many fields optional at schema level. The VEX profile adds a stricter contract for documents whose purpose is to communicate product-specific vulnerability impact.68
A CSAF 2.0 VEX document must satisfy the CSAF Base profile and, in addition, must provide the product and vulnerability structures required by the VEX profile. In practical terms, the profile requires:
document.category = csaf_vex;
a product_tree containing all products referenced later in the document;
a vulnerabilities collection;
for each vulnerability item, at least one of cve or ids;
vulnerability notes;
at least one of the four core VEX status lists: fixed, known_affected, known_not_affected, or under_investigation;
for every product in known_not_affected, a corresponding impact statement represented either by a machine-readable flag or by a threat with category = impact;
for every product in known_affected, a corresponding action statement represented through remediations.
These are not merely editorial recommendations. CSAF defines mandatory tests that reject VEX documents lacking the required product status, vulnerability identity, impact statement, or action statement coverage.69
This creates a useful implementation distinction:
Validation layer
Question
Example failure
JSON Schema
Is the JSON structurally legal CSAF 2.0?
Wrong property type or missing schema-required child
CSAF mandatory tests
Are cross-references and semantic invariants valid?
Product ID referenced but not defined; contradictory statuses
VEX profile tests
Does the document satisfy VEX-specific completeness rules?
known_not_affected without impact statement
Consumer policy
Is this assertion safe to use locally?
Valid document from an unauthorised issuer or for a mismatched product
Table 25: Four distinct validation layers for operational CSAF VEX.
This is one of the major differences from a format that acts primarily as a lightweight statement envelope. CSAF places substantial semantic obligations on the relationship among the document, product tree, vulnerability status, impact explanation, and remediation.
Document envelope and profile identity
A CSAF VEX document is still a CSAF security-advisory document. Its top-level document object establishes the advisory’s identity, publisher, profile, title, and revision lifecycle. A simplified envelope looks like this:
{"document":{"category":"csaf_vex","csaf_version":"2.0","publisher":{"category":"vendor","name":"Example Product Security Team","namespace":"https://security.example.com"},"title":"Example Product VEX for CVE-2021-44228","tracking":{"current_release_date":"2026-08-22T00:30:00Z","id":"EXAMPLE-VEX-2026-0001","initial_release_date":"2026-08-22T00:30:00Z","revision_history":[{"date":"2026-08-22T00:30:00Z","number":"1.0.0","summary":"Initial VEX publication."}],"status":"final","version":"1.0.0"}}}
The example is deliberately incomplete as a VEX document because the profile also requires a product tree and vulnerability information. Its purpose here is only to show the document-level identity and lifecycle fields.
Field
Role
VEX implementation significance
document.category
Profile discriminator
Must be csaf_vex for the CSAF VEX profile
document.csaf_version
Language version
Selects the CSAF 2.0 semantics and validation rules
document.publisher.category
Publisher role
Identifies the type of publishing party
document.publisher.name
Publisher name
Human-readable identity of the issuing party
document.publisher.namespace
Publisher namespace
Participates in globally distinguishing the advisory identity
document.title
Canonical document title
Human-readable advisory identity
document.tracking.id
Advisory identifier
Identifies the advisory within the publisher namespace
document.tracking.version
Current document revision
Tracks advisory evolution; it is not a product version
document.tracking.initial_release_date
Initial publication time
Establishes when this advisory lineage was first released
document.tracking.current_release_date
Current revision publication time
Establishes when the current document revision was released
document.tracking.revision_history
Revision ledger
Records the evolution of the advisory
document.tracking.status
Document lifecycle status
Indicates draft, interim, or final; it is not a vulnerability state
Table 26: CSAF document-level fields most relevant to VEX.
Advisory version is not product version
A recurring identity error is to confuse document.tracking.version with the software release being assessed. The document version describes the current revision of the CSAF advisory. Product versions belong in the product tree.
Therefore:
document.tracking.version = "2.0.0" means version 2.0.0 of the advisory;
a product-tree node representing Example App 4.2.0 describes version 4.2.0 of the product.
A VEX consumer that joins product applicability using the advisory revision is matching the wrong identity domain.
draft, interim, and final describe the document, not the vulnerability
CSAF 2.0 defines draft, interim, and final as values of document.tracking.status.70 These describe the expected lifecycle of the document itself.
interim is especially relevant to VEX because it signals that rapid document updates are expected. It can therefore be useful while a producer is publishing evolving product-impact information. It must not, however, be confused with product_status.under_investigation: the former describes the advisory’s publication lifecycle, while the latter describes uncertainty about a particular product’s vulnerability status.
Likewise, final does not mean that the document can never change. It indicates that the issuer does not currently expect rapid change; subsequent revisions remain possible.
Product identity: the product_tree is the foundation of CSAF VEX
Every product referenced by the VEX statements must be resolvable through the product tree.71 This is not incidental metadata. product_status, flags, remediations, scores, and threats rely on Product IDs that point back into this identity model.
A consumer should therefore conceptually resolve a statement in this order:
locate the Product ID referenced by product_status, flag, remediation, or threat;
resolve that Product ID to a full product definition in product_tree;
inspect the product name, hierarchy, relationships, and identification helpers;
determine whether that defined product state matches the local asset;
only then apply the associated VEX status or action.
CSAF enforces part of this process through a mandatory test: any Product ID referenced outside the full product definition must resolve to a matching Full Product Name in the product tree.72
Product ID is document-local referential identity
CSAF defines product_id as a reference token that must uniquely identify a Full Product Name within the current document. The standard does not prescribe a globally meaningful format for the Product ID.73
establish an internal reference from the VEX status to the product definition. They do not establish that CSAFPID-0001 has any independent meaning outside the document.
A consumer therefore needs stronger product identity than the Product ID token itself.
product_identification_helper: bridge from document identity to real assets
A Full Product Name can include product_identification_helper, which provides one or more ways to match the CSAF product to an external asset database or software inventory. CSAF 2.0 defines helpers including cpe, hashes, model_numbers, purl, sbom_urls, serial_numbers, skus, and x_generic_uris.74
Helper
Best suited to
Main caution
cpe
Platform/product identification in CPE-oriented inventories
CPE precision varies across ecosystems and vendors
purl
Package-level identity
Package identity does not necessarily identify a complete final product
hashes
Exact file/artifact identity
Strong binding but narrow applicability across rebuilds
model_numbers
Hardware or appliance model identity
Often insufficient without software/firmware state
serial_numbers
Specific device populations
Can create highly granular product scope
skus
Commercial product variants
SKU changes can accompany software updates
sbom_urls
Linking the product to its composition evidence
The referenced SBOM still requires its own identity and trust validation
x_generic_uris
Vendor-specific or other governed identifiers
Consumers must understand the identifier namespace
Table 27: CSAF 2.0 product-identification helpers relevant to VEX applicability.
The presence of a Product Identification Helper is not itself enough to prove local applicability. The consumer still needs a matching policy appropriate to the identifier type. A PURL match, an appliance SKU match, and a binary hash match establish different levels and kinds of identity.
CSAF’s optional tests also encourage every Full Product Name to provide a Product Identification Helper. For operational VEX consumption, that is a sensible minimum even where strict profile conformance would not make a particular helper mandatory.
branches: model product hierarchies without losing the final product state
product_tree.branches can model hierarchical identity such as vendor, product family, product name, and product version. This is useful when advisories cover large release matrices, but consumers should not assume that a parent branch automatically has the same vulnerability state as every child.
The VEX status ultimately refers to Product IDs assigned to Full Product Name objects. The hierarchy helps explain and generate those products; the Product ID identifies the actual referential target.
Where branches use product_version_range, CSAF’s optional validation expects the range to use Package URL Version Range (vers) syntax.75 Consumers should therefore avoid inventing their own range semantics when a structured range is available.
relationships: model product combinations as separate product states
CSAF relationships are particularly important for VEX because exploitability can depend on combinations. A relationship connects two existing products and creates a new Full Product Name representing their combination. CSAF 2.0 relationship categories include default_component_of, external_component_of, installed_on, installed_with, and optional_component_of.76
This makes it possible to distinguish, for example:
Application A 4.2.0;
Operating System B;
Application A 4.2.0 installed on Operating System B.
If only the combination is affected, the safest representation is to assign the VEX status to the Product ID of the combined relationship object rather than to the standalone application or operating system.
That directly supports the principle developed in the main article: VEX applies to a defined product state, not merely to a component name.
Product Groups: useful compression with a coverage obligation
product_groups allows several Product IDs to be treated as a named group. This is useful when the same impact statement, remediation, or threat information applies to many products.
However, group-level statements do not weaken the VEX profile’s product-level completeness requirements. If ten products are known_not_affected, every one of those ten Product IDs must be covered by an impact statement, either directly or through a Product Group that contains it. The same principle applies to action statements for known_affected products.77
A group therefore acts as a scope-compression mechanism, not as a way to avoid explicit semantic coverage.
Vulnerability identity: cve, ids, and notes
Each VEX vulnerability item must provide at least one of cve or ids, and it must include notes under the VEX profile.78
For a CVE, use the dedicated cve field:
{"cve":"CVE-2021-44228"}
The more general ids array exists for other vulnerability-tracking systems. CSAF’s optional tests specifically warn against putting a CVE identifier in ids when the dedicated cve field is available.79
This suggests a practical identity rule:
use cve for CVE identifiers;
use ids for other vulnerability namespaces;
preserve enough source-system context to prevent collisions or ambiguous interpretation.
notes provides human-readable vulnerability information and is required by the VEX profile. It should not be used as a substitute for structured status, justification, or remediation fields. A note can explain the vulnerability or assessment context, but the machine-readable VEX semantics still belong in product_status, flags, threats, and remediations.
product_status: eight status lists with four semantic families
First version in a release train known to be affected
Affected boundary
known_affected
Product version is known to be affected
Affected
last_affected
Last version in a release train known to be affected
Affected boundary
first_fixed
First version known to contain a fix
Fixed boundary
fixed
Product version contains a fix
Fixed
known_not_affected
Product version is known not to be affected
Not affected
recommended
Vendor-recommended product version
Recommendation
under_investigation
Impact is not yet known and investigation is ongoing
Under investigation
Table 28: CSAF 2.0 product-status semantics.
The VEX profile requires at least one of the four core lists fixed, known_affected, known_not_affected, or under_investigation for each vulnerability item. The release-boundary fields first_affected, last_affected, first_fixed, and the preference field recommended can add valuable release-train semantics, but they do not by themselves satisfy the VEX profile’s status requirement.81
This is an important difference from a four-state abstraction. CSAF can say not only that a product is affected or fixed, but also where the affected interval begins or ends and which fixed release the vendor recommends.
Contradicting product statuses are a conformance error
CSAF’s mandatory tests group statuses into four mutually exclusive semantic families:
recommended is intentionally different. A product can be recommended even if it belongs to another semantic family, because recommendation is a preference rather than a vulnerability-impact state. The standard explicitly allows this flexibility, including unusual cases where a producer may recommend an otherwise affected version because another version introduces a more severe problem.
known_affected: affected is not the end of the statement
known_affected indicates that the referenced product is known to be affected and that action is recommended. In a CSAF VEX document, every Product ID in known_affected must be covered by product-specific action information in remediations.83
This mirrors the CISA VEX requirement that an affected assertion carry action information.
known_not_affected: status requires a product-scoped impact statement
known_not_affected means that the producer asserts that no remediation is required for the specified vulnerability in the referenced product state. CSAF does not permit that conclusion to stand unexplained in a VEX-profile document. Every known_not_affected Product ID must be covered by an impact statement.84
The impact statement can be represented in either of two ways:
a machine-readable VEX justification in flags;
a human-readable threat with category = impact whose details explain why the vulnerability cannot be exploited.
This dual representation is one of the most important CSAF-specific design choices.
fixed: remediation state, not vulnerability disappearance
fixed says that the referenced product version contains a fix for the vulnerability. It does not mean that the CVE has ceased to exist or that all other versions are fixed.
first_fixed can identify the first release carrying a fix, while recommended can separately identify the version the vendor prefers customers to adopt. Those fields can therefore encode a release progression such as:
last_affected = 4.1.9;
first_fixed = 4.2.0;
fixed = 4.2.0, 4.2.1;
recommended = 4.2.1.
The distinction is useful when a later fixed release is operationally preferable to the first technically corrected build.
under_investigation: uncertainty with an active assessment
under_investigation indicates that it is not yet known whether the product is affected and that investigation is ongoing. The result is expected in a later document revision.85
This is not a neutral placeholder for every unresolved scanner result. It should be used when the producer has entered an assessment process and has not yet reached a final conclusion.
The VEX profile does not impose the same mandatory impact/action statement rules on under_investigation that it imposes on known_not_affected and known_affected. CSAF’s optional tests do, however, warn when an affected or under-investigation product lacks remediation information.86 A strict producer profile can therefore choose to provide explicit interim guidance even while technical investigation continues.
flags: machine-readable reasons for known_not_affected
flags contains product-specific machine-readable labels. Each flag must carry a label and must identify the products to which it applies through product_ids, group_ids, or both.87
For VEX, CSAF 2.0 defines the five CISA-style not-affected justification labels:
Flag label
Meaning
component_not_present
The vulnerable component is not present in the product
vulnerable_code_not_present
The component can be present, but the vulnerable code is absent
vulnerable_code_cannot_be_controlled_by_adversary
Vulnerable code exists, but an attacker cannot exercise the required control
vulnerable_code_not_in_execute_path
Vulnerable code is not reachable through product execution paths
The critical semantic property is scope agreement: the Product ID in known_not_affected must actually be covered by the flag.
A flag without a product reference is invalid
CSAF defines a mandatory test requiring every flag to identify at least one product_id or group_id.88 A bare justification such as component_not_present is insufficient because the consumer cannot know which product the assertion qualifies.
This is a useful contrast with formats where the statement envelope supplies product scope outside the justification object. In CSAF, the justification itself carries explicit product or group references.
Multiple VEX justification flags for the same product are prohibited
CSAF also defines a mandatory test preventing the same Product ID from being covered by more than one flag carrying a VEX justification code for the same vulnerability, including indirect coverage through Product Groups.89
This rule prevents an implementation from simultaneously asserting, for example, that the component is absent and that the vulnerable code is present but unreachable for the same product/vulnerability pair. Those statements may arise from different investigation branches, but the published machine-readable justification should converge on one coherent reason.
A threat item can describe information that changes as knowledge of the vulnerability evolves. CSAF defines three threat categories: exploit_status, impact, and target_set.90
For VEX, category = impact has a special role: it can provide the required human-readable explanation for a known_not_affected product.
For example:
{"threats":[{"category":"impact","details":"The product embeds the dependency but does not include the vulnerable lookup implementation in the released artifact.","product_ids":["CSAFPID-0001"]}]}
When used as the VEX impact statement, the details must explain why the vulnerability cannot be exploited for the scoped product.91
This gives CSAF two different but complementary ways to carry the not-affected basis:
Limited to the five defined VEX justification labels
threats[category=impact]
Rich human-readable product-specific explanation
Harder to automate consistently
Table 30: Two CSAF 2.0 representations for a VEX impact statement.
A strong producer can use both: the flag supplies standardized semantics, while the impact threat supplies enough technical explanation for a reviewer to understand the reasoning.
remediations: the action statement for affected products
remediations provides product-scoped instructions for handling the vulnerability. Each remediation requires category and details, and it must identify the applicable products through product_ids, group_ids, or both.92
CSAF 2.0 defines five remediation categories:
Category
Meaning
Security interpretation
vendor_fix
Official fix issued by the product author
Intended to resolve the vulnerability
mitigation
Configuration or deployment change that reduces risk
Risk reduction; vulnerability can remain present
workaround
Configuration/deployment approach that avoids exposure
Temporary or situational avoidance
none_available
No fix or remediation is currently available
Affected condition can remain unresolved
no_fix_planned
No fix is planned
Disposition decision, often for end-of-life products
Table 31: CSAF 2.0 remediation categories.
The VEX profile explicitly permits none_available and no_fix_planned as action statements for known_affected products.93 This is important because an action statement does not necessarily mean that a patch exists.
For example:
{"product_status":{"known_affected":["CSAFPID-0002"]},"remediations":[{"category":"vendor_fix","details":"Upgrade to Example App 4.2.1 or later.","product_ids":["CSAFPID-0002"],"url":"https://security.example.com/advisories/CVE-2021-44228"}]}
is complete at the VEX profile level because the known-affected product has an applicable action statement.
By contrast, known_affected without a remediation covering the same Product ID fails the VEX action-statement requirement.
mitigation is not fixed
A mitigation can reduce exploitation likelihood or impact without removing the vulnerability from the product. Therefore:
product_status.known_affected can coexist with a remediation.category = mitigation;
the presence of a mitigation must not be translated automatically into known_not_affected;
a later document revision may move the product to fixed if an actual corrective release is issued.
This separation between status and response is central to reliable interoperability.
none_available and no_fix_planned are not not-affected states
Both categories describe the action situation for a product that can remain affected. none_available means no remediation is currently available; no_fix_planned means the producer does not plan to provide one.
Neither category justifies suppressing the vulnerability as known_not_affected.
Product Groups and cross-field coverage
CSAF allows threats and remediations to refer to Product Groups even though product_status itself contains Product IDs. This is useful for compact documents, but it creates a coverage problem that implementers must solve explicitly.94
Suppose the product tree defines:
{"product_groups":[{"group_id":"CSAFGID-0001","product_ids":["CSAFPID-0001","CSAFPID-0002"],"summary":"Two products sharing the same VEX assessment"}]}
A single impact threat can then cover both products:
{"threats":[{"category":"impact","details":"The vulnerable component is absent from both released products.","group_ids":["CSAFGID-0001"]}]}
If known_not_affected also contains CSAFPID-0003, however, that third product remains uncovered unless another impact statement applies to it. The presence of one group-level statement does not satisfy the requirement for products outside the group.
The same logic applies to remediations for known_affected.
A safe consumer or validator should therefore expand group membership before evaluating VEX completeness:
collect every Product ID in the relevant product_status list;
collect direct product_ids from applicable flags, threats, or remediations;
resolve every referenced group_id to its Product IDs;
compute the complete covered set;
verify that every status Product ID has the required impact or action statement.
This is one of the places where CSAF VEX clearly behaves as a graph of cross-referenced objects rather than as a flat vulnerability record.
Release-train semantics: first_affected, last_affected, first_fixed, and recommended
The four additional status lists are especially useful when a vulnerability spans a release train.
Consider a simplified product family:
Version
CSAF status
4.0.0
first_affected
4.0.0–4.1.9
known_affected
4.1.9
last_affected
4.2.0
first_fixed, fixed
4.2.1
fixed, recommended
This representation captures more than a single affected/fixed Boolean. It tells the consumer where the affected interval begins and ends, where the first correction appeared, and which corrected release the vendor currently recommends.
Consumers should nevertheless avoid inferring version ordering from display names alone. The product tree remains the authoritative representation of the individual product states, and any range semantics should be interpreted according to the product-tree model rather than by generic string comparison.
Vulnerability scores and VEX status are different dimensions
CSAF can attach CVSS scores to specific Product IDs through scores. That allows product-specific scoring rather than treating the vulnerability’s upstream score as universally applicable.95
A score should therefore answer a risk/severity question for the scoped product, while product_status answers the VEX impact-state question.
These concepts should not be collapsed:
a product can be known_not_affected even when the upstream vulnerability has a critical score;
a fixed product need not retain the affected product’s score;
an affected product can receive a product-specific CVSS vector that differs from an upstream database score because deployment context changes exploitability or impact metrics.
CSAF’s optional tests warn if affected products lack scores and if fixed products retain inappropriate CVSS scoring. Those tests are quality signals rather than the core VEX status model.
Threat information is not the same as VEX status
threats can carry exploit_status, impact, or target_set. These fields can change as real-world knowledge evolves, but they answer different questions from product_status.
For example:
product_status.known_affected means the product is affected;
threats[category=exploit_status] can describe whether exploit code is theoretical, public, weaponized, or actively used;
threats[category=target_set] can describe the population known to be targeted.
An affected VEX state therefore does not imply active exploitation. Conversely, active exploitation evidence does not eliminate the need to establish which product state is actually affected.
This distinction is particularly important if CSAF VEX information is later consumed in a CRA Article 14 workflow: known_affected is a product-impact conclusion, whereas active exploitation is a separate threat-evidence proposition.
Document lifecycle and VEX reassessment
CSAF’s document-tracking model is richer than a single VEX timestamp. The tracking object requires current_release_date, id, initial_release_date, revision_history, status, and version.96
A useful operational interpretation is:
Field
Lifecycle question
tracking.id
Which advisory lineage is this?
tracking.initial_release_date
When was this advisory first published?
tracking.current_release_date
When was this revision published?
tracking.version
Which revision is current?
tracking.revision_history
What changed over the advisory’s life?
tracking.status
Does the issuer expect rapid further updates?
Table 32: CSAF document lifecycle fields relevant to VEX reassessment.
The current document version must agree with the latest revision-history entry according to CSAF’s mandatory tests, and revision history must progress coherently.97
For VEX consumers, the more important point is that document freshness is not equivalent to assessment validity. A document published yesterday can already be inapplicable if the local product has changed, while an older VEX assertion can remain valid for an immutable product artifact if its assumptions and scope still hold.
The VEX pipeline should therefore distinguish:
advisory revision freshness;
product-version or artifact applicability;
product-configuration assumptions;
vulnerability-intelligence changes;
new exploitation or incident evidence.
Any of these can trigger reassessment.
A strict CSAF VEX producer profile
The normative VEX profile already imposes substantial requirements, but organisations can layer a stricter operational policy on top of it. A defensible internal producer profile might require:
This is not CSAF schema syntax and must not be presented as an alternative standard. It is a semantic quality profile for an organisation that wants VEX to drive automated or semi-automated vulnerability disposition.
The profile should also require machine validation against:
the CSAF 2.0 JSON Schema;
all CSAF mandatory tests;
the VEX profile-specific tests;
the organisation’s own identity, issuer, freshness, and evidence policies.
Recommended state-specific producer rules
A practical producer policy can make the four core VEX statuses operationally explicit:
Core VEX status
Recommended producer rule
known_not_affected
Provide product-specific impact coverage, use a VEX flag where one of the five standard justifications applies, add human-readable impact reasoning when useful, and link the internal evidence record
known_affected
Provide product-specific remediation/action information and enough detail for the consumer to act
fixed
Identify the corrected product version or product state; use first_fixed and recommended where they add release-train meaning
under_investigation
State that assessment is active, avoid implying safety, publish interim guidance where useful, and update the advisory when the investigation resolves
Table 33: Example state-specific producer policy layered on CSAF 2.0.
Worked Log4Shell model: four product states in one CSAF VEX document
The following example applies the main article’s four Log4Shell product states to CSAF 2.0:
Product A: the vulnerable component is not present, so the product is known_not_affected;
Product B: the vulnerable component and exploitable behavior are present, so the product is known_affected;
Product C: the product is a corrected release, so it is fixed;
Product U: investigation is active but incomplete, so it is under_investigation.
The example is intentionally compact, but it preserves the essential CSAF VEX relationships among product identity, vulnerability identity, status, not-affected justification, and remediation.
{"document":{"category":"csaf_vex","csaf_version":"2.0","publisher":{"category":"vendor","name":"Example Product Security Team","namespace":"https://security.example.com"},"title":"Example Product VEX for CVE-2021-44228","tracking":{"current_release_date":"2026-08-22T00:30:00Z","id":"EXAMPLE-VEX-2026-0001","initial_release_date":"2026-08-22T00:30:00Z","revision_history":[{"date":"2026-08-22T00:30:00Z","number":"1.0.0","summary":"Initial VEX publication."}],"status":"final","version":"1.0.0"}},"product_tree":{"full_product_names":[{"name":"Example Product A 1.0.0","product_id":"CSAFPID-A","product_identification_helper":{"purl":"pkg:generic/example/product-a@1.0.0"}},{"name":"Example Product B 1.0.0","product_id":"CSAFPID-B","product_identification_helper":{"purl":"pkg:generic/example/product-b@1.0.0"}},{"name":"Example Product C 1.1.0","product_id":"CSAFPID-C","product_identification_helper":{"purl":"pkg:generic/example/product-c@1.1.0"}},{"name":"Example Product U 1.0.0","product_id":"CSAFPID-U","product_identification_helper":{"purl":"pkg:generic/example/product-u@1.0.0"}}]},"vulnerabilities":[{"cve":"CVE-2021-44228","notes":[{"category":"summary","text":"Product-specific VEX assessment for Apache Log4j CVE-2021-44228."}],"flags":[{"label":"component_not_present","product_ids":["CSAFPID-A"]}],"product_status":{"fixed":["CSAFPID-C"],"known_affected":["CSAFPID-B"],"known_not_affected":["CSAFPID-A"],"recommended":["CSAFPID-C"],"under_investigation":["CSAFPID-U"]},"remediations":[{"category":"vendor_fix","details":"Upgrade Product B to the vendor's corrected release line represented by Product C or a later supported fixed release.","product_ids":["CSAFPID-B"],"url":"https://security.example.com/advisories/CVE-2021-44228"},{"category":"none_available","details":"Product U remains under investigation; no product-specific remediation recommendation is available until the assessment is complete.","product_ids":["CSAFPID-U"]}],"threats":[{"category":"impact","details":"Product A does not contain the vulnerable component and therefore cannot execute the vulnerable Log4j code path.","product_ids":["CSAFPID-A"]}]}]}
Read semantically, the document communicates four different conclusions without collapsing them:
Product
Status
Additional CSAF semantics
Product A
known_not_affected
component_not_present flag plus human-readable impact statement
Product B
known_affected
vendor_fix remediation supplies the action statement
Product C
fixed, recommended
Corrected product state and preferred upgrade target
Product U
under_investigation
Investigation remains unresolved; interim none_available remediation makes the lack of current action explicit
Table 34: Semantic interpretation of the worked CSAF Log4Shell example.
The Product A reasoning is intentionally stronger than merely observing that log4j-api or another Log4j-related artifact exists somewhere in a dependency graph. component_not_present should only be used if the actual vulnerable component relevant to CVE-2021-44228 is absent from the assessed product state.
Product B demonstrates the opposite case: once the technical assessment establishes affected status, CSAF requires an action statement. The remediation provides that product-specific action without changing the status itself.
Product C illustrates why fixed and recommended are separate fields. A version can contain a fix without necessarily being the producer’s preferred upgrade target; using both fields allows the document to distinguish technical correction from release recommendation.
Product U demonstrates temporal uncertainty. under_investigation communicates that assessment is active and unresolved. The document can be revised later so that Product U moves into one of the final semantic families without rewriting the historical meaning of the previous document version.
Group-scoped Log4Shell example
Suppose three appliance versions all exclude log4j-core and therefore share the same not-affected justification. Instead of duplicating the impact statement three times, the producer can define a Product Group:
{"product_groups":[{"group_id":"CSAFGID-NO-LOG4J-CORE","product_ids":["CSAFPID-A1","CSAFPID-A2","CSAFPID-A3"],"summary":"Released appliance versions that do not contain log4j-core"}]}
This is semantically compact because expansion of the Product Group covers every Product ID in known_not_affected.
If a fourth Product ID were added to known_not_affected but not to the group and not to another applicable impact statement, the VEX profile’s coverage requirement would fail. The validator must therefore reason over resolved group membership rather than comparing arrays textually.
Relationship-scoped example: exploitability depends on deployment combination
Product relationships become valuable when vulnerability impact depends on an installed combination rather than a standalone package.
Consider:
CSAFPID-APP: Example Application 4.2.0;
CSAFPID-OS: Example Operating System 12;
CSAFPID-COMBINATION: Example Application 4.2.0 installed on Example Operating System 12.
A relationship can represent the combined product state:
{"relationships":[{"category":"installed_on","full_product_name":{"name":"Example Application 4.2.0 installed on Example Operating System 12","product_id":"CSAFPID-COMBINATION","product_identification_helper":{"x_generic_uris":[{"namespace":"https://security.example.com/product-state/","uri":"https://security.example.com/product-state/app-4.2.0-on-os-12"}]}},"product_reference":"CSAFPID-APP","relates_to_product_reference":"CSAFPID-OS"}]}
If the vulnerability is exploitable only in that combination, the VEX status should refer to CSAFPID-COMBINATION. Marking the standalone application known_affected would overstate scope; marking the operating system known_affected would misidentify the subject.
This is a concrete example of why product identity is part of the security conclusion rather than a clerical field.
Consumer-side acceptance sequence
A CSAF consumer should not begin by searching for known_not_affected. It should first establish whether the document and its references are trustworthy and applicable.
A robust interpretation sequence is:
validate the document against the CSAF 2.0 JSON Schema;
run the CSAF mandatory tests;
confirm document.category = csaf_vex and validate the VEX profile requirements;
authenticate the source and establish that the publisher is authorised for the claimed product scope;
resolve every Product ID and Product Group reference;
match the referenced product state to the local asset using appropriate identification helpers and relationships;
identify the vulnerability through cve or ids;
read the applicable product_status;
if the status is known_not_affected, verify that the product is covered by a valid flag or impact threat;
if the status is known_affected, verify that the product is covered by an applicable remediation/action statement;
evaluate document and assessment freshness;
apply local policy before changing vulnerability disposition.
That sequence prevents a consumer from accepting a syntactically correct but semantically unrelated statement.
Schema validity, profile conformance, and technical truth
CSAF 2.0 goes further than many interchange formats in defining mandatory semantic tests and profile-specific completeness rules. That is a major strength. It still cannot make the underlying product-security assessment true merely by encoding it correctly.
A consumer considering whether a known_not_affected statement may suppress a finding should therefore establish all of the following:
Schema validity: the JSON document conforms to CSAF 2.0.
Mandatory-test validity: cross-references, statuses, identifiers, and other CSAF invariants pass the required tests.
VEX profile conformance: the document satisfies the csaf_vex profile, including impact/action coverage.
Issuer authentication: the source is authenticated.
Issuer authority: the issuer is authorised to make the product-specific assertion.
Product applicability: the referenced Product ID resolves to the actual local product state.
Vulnerability applicability: the correct vulnerability identity is being interpreted.
Semantic coherence: product status, flags, threats, remediation, release boundaries, and product relationships do not contradict one another.
Freshness: the product state and assumptions underlying the assessment remain valid.
Evidence support: the technical assessment is supported strongly enough for the intended disposition.
Local-policy acceptance: the consumer’s vulnerability-management policy permits the CSAF assertion to alter the finding.
This hierarchy clarifies what CSAF can and cannot do. CSAF can make the communication contract much stronger by requiring explicit product references, status semantics, impact explanations, action statements, and lifecycle information. It cannot replace the build evidence, architecture analysis, reachability analysis, exploit testing, supplier evidence, or engineering judgment that made the assessment defensible in the first place.
The architectural lesson from CSAF
CSAF demonstrates that VEX can be much more than a compact (product, vulnerability, status) record. In the CSAF model, the VEX conclusion is embedded in an advisory graph whose meaning depends on resolved product identity, product hierarchy and relationships, vulnerability identity, product-status membership, scoped impact statements, scoped remediation actions, and document lifecycle.
That additional structure creates implementation cost, but it also creates opportunities for stronger automation. A conforming consumer can reject undefined product references, contradictory statuses, unscoped flags, uncovered not-affected products, and uncovered affected products before those defects reach vulnerability-disposition logic.
The resulting design principle is therefore:
CSAF VEX should be consumed as a profile-constrained, cross-referenced advisory model, not as a collection of status arrays.
When used correctly, the product tree answers what exact product state is being discussed; product_status answers what the producer currently concludes; flags or impact threats answer why a not-affected conclusion is justified; remediations answer what an affected consumer should do; and tracking metadata answers which advisory revision carries those claims.
The richer evidence package should remain outside, or be linked from, the VEX serialization. That preserves the distinction developed throughout the article: CSAF VEX is a structured and strongly constrained communication of a product-specific vulnerability assessment; it is not a substitute for the assessment itself.
Cybersecurity and Infrastructure Security Agency. (2025). 2025 Minimum Elements for a Software Bill of Materials (SBOM). CISA. Official resource↩︎
National Telecommunications and Information Administration. (2021). The Minimum Elements for a Software Bill of Materials (SBOM). U.S. Department of Commerce. Official report↩︎
European Union Agency for Cybersecurity. (2022). NFV Security in 5G: Challenges and Best Practices. ENISA. Official report↩︎
Cybersecurity and Infrastructure Security Agency. (2023). Minimum Requirements for Vulnerability Exploitability eXchange (VEX). CISA. Official resource↩︎
Cybersecurity and Infrastructure Security Agency. (2025). 2025 Minimum Elements for a Software Bill of Materials (SBOM). CISA. Official resource↩︎
European Parliament and Council of the European Union. (2024). Regulation (EU) 2024/2847 on horizontal cybersecurity requirements for products with digital elements. Official Journal of the European Union. Official text↩︎
Montano, A. (2026). Cyber Resilience Act: The New Product-Security Baseline. Random Bits of Knowledge. Article↩︎
European Parliament and Council of the European Union. (2024). Regulation (EU) 2024/2847 on horizontal cybersecurity requirements for products with digital elements. Official Journal of the European Union. Official text↩︎
European Parliament and Council of the European Union. (2024). Regulation (EU) 2024/2847 on horizontal cybersecurity requirements for products with digital elements. Official Journal of the European Union. Official text↩︎
European Commission. (2026). Cyber Resilience Act — Reporting Obligations. Shaping Europe’s Digital Future. Official implementation page↩︎
Montano, A. (2026). Does the CRA Require Vulnerability Scanning from 11 September 2026? No, but It Does Require a Reporting Decision Process. Random Bits of Knowledge. Article↩︎
European Parliament and Council of the European Union. (2024). Regulation (EU) 2024/2847 on horizontal cybersecurity requirements for products with digital elements. Official Journal of the European Union. Official text↩︎
European Commission. (2026). Cyber Resilience Act — Reporting Obligations. Shaping Europe’s Digital Future. Official implementation page↩︎
European Parliament and Council of the European Union. (2024). Regulation (EU) 2024/2847 on horizontal cybersecurity requirements for products with digital elements. Official Journal of the European Union. Official text↩︎
Montano, A. (2026). Cyber Resilience Act: The New Product-Security Baseline. Random Bits of Knowledge. Article↩︎
Montano, A. (2026). Does the CRA Require Vulnerability Scanning from 11 September 2026? No, but It Does Require a Reporting Decision Process. Random Bits of Knowledge. Article↩︎
OWASP Foundation. (2026). Vulnerability Exploitability: JSON and XML examples. CycloneDX Security Use Cases. As checked on 22 August 2026, the displayed JSON example uses analysis.state = not_affected while the corresponding XML example uses analysis.state = exploitable; both mark the illustrated version range unaffected. Official use case.↩︎
OASIS Open. (2024). Common Security Advisory Framework Version 2.0 Errata 01. OASIS Approved Errata, 26 January 2024. The errata changes the aggregator schema only; it does not change the CSAF document or CSAF JSON schema. Approved Errata.↩︎
OASIS Open. (2026). Common Security Advisory Framework Version 2.1, Committee Specification Draft 02. 25 February 2026. CSAF 2.1 CSD02.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, product-tree and Full Product Name definitions. Defines Product IDs as document-scoped reference tokens and the product tree as the container for referencable products. CSAF 2.0 product model.↩︎
OASIS Open. CSAF 2.0 mandatory and optional tests. Includes missing/duplicate Product ID tests, contradicting product status, PURL validation, revision-history consistency, missing Product Identification Helper warnings, and other semantic checks. CSAF 2.0 validation tests.↩︎
OASIS Open. CSAF 2.0, product-tree and Full Product Name definitions. Defines Product IDs as document-scoped reference tokens and the product tree as the container for referencable products. CSAF 2.0 product model.↩︎
OASIS Open. CSAF 2.0, Full Product Name - Product Identification Helper. Defines cpe, hashes, model_numbers, purl, sbom_urls, serial_numbers, skus, and x_generic_uris. CSAF 2.0 product identification helpers.↩︎
OASIS Open. CSAF 2.0 mandatory and optional tests. Includes missing/duplicate Product ID tests, contradicting product status, PURL validation, revision-history consistency, missing Product Identification Helper warnings, and other semantic checks. CSAF 2.0 validation tests.↩︎
OASIS Open. CSAF 2.0, Product Tree - Relationships. Defines product combinations and relationship categories including installed_on, installed_with, and component relationships. CSAF 2.0 product relationships.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0 mandatory and optional tests. Includes missing/duplicate Product ID tests, contradicting product status, PURL validation, revision-history consistency, missing Product Identification Helper warnings, and other semantic checks. CSAF 2.0 validation tests.↩︎
OASIS Open. CSAF 2.0, section 3.2.3.9: Vulnerabilities Property - Product Status. Defines the eight product-status lists and their semantics. CSAF 2.0 product status.↩︎
OASIS Open. CSAF 2.0 mandatory and optional tests. Includes missing/duplicate Product ID tests, contradicting product status, PURL validation, revision-history consistency, missing Product Identification Helper warnings, and other semantic checks. CSAF 2.0 validation tests.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, section 3.2.3.9: Vulnerabilities Property - Product Status. Defines the eight product-status lists and their semantics. CSAF 2.0 product status.↩︎
OASIS Open. CSAF 2.0, section 6.2: Optional Tests. Includes the warning for missing remediation on affected and under-investigation Product IDs. CSAF 2.0 optional tests.↩︎
OASIS Open. CSAF 2.0, section 3.2.3.5 and mandatory flag tests. Defines product-scoped flags, the five VEX justification labels, and mandatory product-reference and uniqueness tests. CSAF 2.0 flags.↩︎
OASIS Open. CSAF 2.0, section 3.2.3.5 and mandatory flag tests. Defines product-scoped flags, the five VEX justification labels, and mandatory product-reference and uniqueness tests. CSAF 2.0 flags.↩︎
OASIS Open. CSAF 2.0, section 3.2.3.5 and mandatory flag tests. Defines product-scoped flags, the five VEX justification labels, and mandatory product-reference and uniqueness tests. CSAF 2.0 flags.↩︎
OASIS Open. CSAF 2.0, sections 3.2.3.13-3.2.3.14: Scores and Threats. Defines product-scoped CVSS scores and the threat categories exploit_status, impact, and target_set. CSAF 2.0 vulnerability context.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, section 3.2.3.12: Remediations. Defines mitigation, no_fix_planned, none_available, vendor_fix, and workaround, together with product/group scoping. CSAF 2.0 remediations.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, section 4.5: Profile 5: VEX. Defines the csaf_vex profile, required product tree and vulnerability structures, the four core VEX status families, impact statements for known_not_affected, and action statements for known_affected. CSAF 2.0 VEX profile.↩︎
OASIS Open. CSAF 2.0, sections 3.2.3.13-3.2.3.14: Scores and Threats. Defines product-scoped CVSS scores and the threat categories exploit_status, impact, and target_set. CSAF 2.0 vulnerability context.↩︎
@online{montano2022,
author = {Montano, Antonio},
title = {VEX {Standards} from {First} {Principles}},
date = {2022-12-03},
url = {https://antomon.github.io/longforms/vex-standards-from-first-principles/},
langid = {en},
abstract = {Software Bills of Materials (SBOMs) and Vulnerability
Exploitability eXchange (VEX) address different stages of the
software-vulnerability lifecycle. An SBOM establishes a structured
representation of software composition; it does not determine
whether every vulnerability associated with an included component
affects the finished product. VEX addresses that second problem by
communicating a scoped product-specific assessment: whether a
vulnerability is affected, not affected, fixed, or under
investigation, together with the justification, impact, or action
information needed to interpret that conclusion. Starting from this
separation, the article develops an end-to-end model that links
product identity, SBOM evidence, vulnerability correlation,
technical investigation, assessment, VEX publication, consumer
acceptance, reassessment, and auditable vulnerability disposition.
The article then compares the principal VEX implementation
architectures as distinct semantic models rather than
interchangeable serializations. CSAF embeds VEX in a structured
security-advisory framework; CycloneDX integrates applicability and
product-impact analysis into a Bill-of-Materials model; SPDX 3
represents VEX through first-class typed security relationships; and
OpenVEX provides a lightweight, SBOM-agnostic statement format.
Their concepts overlap, but product identity, status vocabularies,
justification taxonomies, remediation semantics, provenance, version
applicability, and lifecycle information do not map one-to-one. A
worked analysis of CVE-2021-44228 shows why component presence,
vulnerable-code presence, reachability, adversary control,
mitigation, remediation, and uncertainty must remain distinct before
a defensible VEX conclusion can be issued. The implementation
discussion extends this analysis into CI/CD automation, trust
boundaries, interoperability, semantic-loss handling, reversible
suppression, and consumer-side acceptance policy. A dedicated
CycloneDX 1.7 implementation appendix then moves from architecture
to field-level practice, explaining how document identity, product
identity, `affects`, version applicability, `analysis`,
justifications, lifecycle metadata, provenance, completeness,
signatures, producer profiles, and consumer validation interact in a
defensible VEX workflow. The Cyber Resilience Act (CRA) gives this
distinction practical regulatory significance in the European
context. Regulation (EU) 2024/2847 incorporates SBOM creation into
manufacturers’ vulnerability-handling obligations under the full CRA
regime, while it does not mandate VEX or any particular VEX
serialization. VEX can nevertheless support CRA operations by
communicating product-specific vulnerability conclusions, improving
supplier and product-security workflows, and contributing evidence
to Article 14 reporting decisions. It cannot, by itself, establish
active exploitation, legal reportability, conformity, or the absence
of remediation obligations. The resulting implementation principle
is that software-composition evidence, product-specific
vulnerability assessment, VEX communication, exploitation or
incident evidence, and regulatory decision records should remain
distinct but traceably connected. Safe automation therefore depends
on precise product identity, evidence-backed assessments,
authenticated and authorized issuers, preservation of semantic
scope, explicit conflict handling, reversible disposition changes,
and reassessment whenever the assumptions underlying a VEX statement
cease to hold.}
}