A VEX (Vulnerability Exploitability eXchange) statement is a machine-readable document in which a software supplier asserts, per vulnerability and per product, one of four statuses: not_affected, affected, fixed, or under_investigation — turning "our scanner found CVE-X in your product" into a question with an authoritative, automatable answer. VEX exists because SBOMs created a new problem while solving an old one: once customers can see every component in your product, their scanners light up with every CVE in every component, and most of those findings don't apply. VEX is the supplier's channel for saying which ones do.
The concept came out of the NTIA/CISA SBOM working groups around 2021, precisely because early SBOM adopters found themselves drowning in support tickets asking "are you affected by CVE-whatever?"
The problem VEX solves, with numbers
Take a container image with 180 OS packages and 60 application dependencies. Grype or Trivy will typically report 400–900 CVE matches on a mainstream base image. Of those, the fraction that is actually exploitable in the shipped configuration is routinely under 10% — the vulnerable function isn't called, the affected feature is compiled out, a mitigating control blocks the path, or the code never executes with attacker-reachable input.
Without VEX, every one of your customers re-derives that analysis independently, badly, and then emails you. During Log4Shell, vendors fielded thousands of identical "are you affected?" tickets. The ones with a published machine-readable statement answered once; everyone else answered one customer at a time. A not_affected VEX statement is triage work done once by the party with source access, then distributed to every consumer.
The four statuses and the justification requirement
| Status | Meaning | Required extras |
|---|---|---|
not_affected | The vulnerability cannot be exploited in this product | A justification (machine-readable) |
affected | Exploitable; consumer should act | Recommended: action statement ("upgrade to 2.4.1") |
fixed | This product version contains the remediation | Version info |
under_investigation | Analysis in progress | Should be updated later — and often isn't |
The not_affected justifications are where VEX earns its keep, because they're constrained to a small enumerated set (in OpenVEX): component_not_present, vulnerable_code_not_present, vulnerable_code_not_in_execute_path, vulnerable_code_cannot_be_controlled_by_adversary, and inline_mitigations_already_exist. That enumeration is deliberate — it forces the supplier to say why in a way a policy engine can evaluate, rather than free-texting "we assessed this as low risk."
Note the overlap with reachability: vulnerable_code_not_in_execute_path is literally a reachability analysis verdict serialized into an exchange format. Tools that compute reachability can emit VEX; that's the intended pipeline.
Three formats, one idea
VEX is a concept, not a single schema, which causes predictable confusion:
- OpenVEX — minimal JSON, Sigstore-community backed, easiest to generate and diff. A complete document fits in 20 lines.
- CycloneDX VEX — vulnerability data embedded in (or referencing) a CycloneDX BOM via the
vulnerabilitiesarray. Natural if your SBOM pipeline is already CycloneDX. - CSAF 2.0 VEX profile — OASIS standard, the heavyweight option used by large vendors (Red Hat, Cisco, Oracle publish CSAF). Expressive product trees, correspondingly painful to hand-author.
A minimal OpenVEX statement:
{
"@context": "https://openvex.dev/ns/v0.2.0",
"author": "Acme Product Security",
"statements": [
{
"vulnerability": { "name": "CVE-2024-3094" },
"products": [
{ "@id": "pkg:oci/acme-api@sha256:c1b2..." }
],
"status": "not_affected",
"justification": "component_not_present"
}
]
}
Note the product identifier is a purl with a digest — VEX statements should bind to exact artifacts, same as provenance, or consumers can't match them reliably.
Consuming VEX: where it actually changes scanner output
Publishing VEX is half the loop; the other half is scanners honoring it. Current state of tooling:
# Trivy: suppress findings using a VEX document
trivy image --vex openvex.json acme-api:1.4
# Grype: same idea
grype acme-api:1.4 --vex openvex.json
# vexctl: create and merge statements
vexctl create --product="pkg:oci/acme-api@sha256:c1b2..." \
--vuln="CVE-2024-3094" --status="not_affected" \
--justification="component_not_present"
Kubernetes-side, admission policies can require that any affected finding above a CVSS threshold either be fixed or carry an explicit acceptance. Vulnerability management platforms increasingly treat VEX as a first-class input and output — Safeguard's SCA both consumes supplier VEX to suppress non-applicable findings and exports VEX from its own reachability verdicts, and its SBOM tooling keeps the statements attached to the component inventory they describe. The dry reality: VEX consumption across the industry still lags generation badly, so check what your scanner actually does with a VEX document before building process around it.
Failure modes worth knowing before you rely on VEX
- Stale
under_investigation. The status exists to buy time, and some vendors let it rot for months. Treat anunder_investigationolder than 30 days asaffectedin your policy. - Self-attestation with no evidence. VEX is an assertion, not a proof. A supplier can claim
not_affectedincorrectly or dishonestly. The justification enum helps; asking for the analysis behind load-bearing statements helps more. - Product identity mismatches. If the supplier's VEX references
pkg:maven/com.acme/apiand your scanner seespkg:oci/acme-api, nothing matches and the VEX silently does nothing. Digest-pinned purls are the fix. - VEX as suppression laundering. Internally generated VEX that nobody reviews becomes a quiet way to make findings disappear. Route
not_affectedstatements through the same review you'd give a risk acceptance.
Frequently asked questions
Is VEX a replacement for an SBOM?
No — they're complements. An SBOM says what's inside; VEX says which known vulnerabilities in those components actually matter for the product. CISA's framing is that SBOM without VEX generates noise, and VEX without SBOM lacks the inventory to bind statements to.
Who should issue VEX statements?
Primarily the software supplier, since they have source access and know the build configuration. But downstream parties issue VEX too: an internal platform team can publish VEX for the container images it curates, recording its own exploitability analysis for internal consumers.
Can a VEX statement change over time?
Yes, and that's by design — statements carry timestamps and documents are versioned. A CVE can move from under_investigation to not_affected, or from not_affected to affected when new research lands. Consumers should always take the latest statement for a given product-vulnerability pair.
Does VEX satisfy regulators?
Increasingly it's the expected mechanism: CISA has published VEX guidance, the EU CRA's vulnerability-handling obligations map naturally onto it, and FDA premarket cybersecurity submissions reference exploitability assessment alongside SBOMs. None of them mandate a specific format yet, so pick the one your tooling can actually produce and validate.