The moat

Evidence-backed VEX: prove exploitability, don't assert it

Every VEX file you publish makes a claim about your product. In almost every tool, that claim is a human’s judgement written down. Evidence-backed VEX puts a determination behind it instead — reachability analysis and an exploitation attempt, attached to the status. Here is what that means, and why it decides how much you have to report under the CRA.

Updated 7 Jul 2026·~9 min read·For product security teams

A modern application is mostly other people's code. When a CVE lands against one of your dependencies, the first question isn't "is there a vulnerability" — a scanner answers that in seconds — it's "does it matter here?" VEX is the standard way to record the answer. The trouble is what usually stands behind that answer: not much.

What VEX is, in one paragraph

VEX — Vulnerability Exploitability eXchange — is a machine-readable statement about whether a known vulnerability affects a specific product. Each statement carries one of four statuses: not_affected, affected, fixed, or under_investigation. It travels alongside an SBOM (which lists what's in the product) and answers the question the SBOM raises but can't settle: which of these components actually expose us. Three formats dominate — CycloneDX VEX, OpenVEX and the CSAF VEX profile — and they're interoperable enough that a downstream consumer can ingest any of them.

The single most useful thing VEX does is let you say not_affected. A component may carry a scary CVE that simply doesn't reach your product — wrong configuration, dead code path, a function you never call. Marking it not_affected takes it off the remediation queue and, under the CRA, off the reporting queue. Which is exactly why the basis for that word matters so much.

The assertion problem

Here is how a not_affected gets written in most organisations today. An engineer reads the advisory, looks at how the component is used, forms a view, and types the status into a VEX document. The tooling around them — SBOM platforms, SCA scanners — helps record and export that view. None of it checks whether the view is correct.

That's an assertion, and an assertion has two problems. It's unverifiable: nobody downstream, and nobody in an audit, can reconstruct the reasoning six months later. And it's indefensible: when a market-surveillance authority asks why a given vulnerability wasn't reported, "our engineer judged it not affected" is a signature, not evidence.

Everyone can annotate a VEX file. Almost nobody can back it. That gap is the whole opportunity.

The industry has quietly conceded this. The consensus view of the CRA's 24-hour clock is that tools automate the alerting but the assessment — is our product really affected? — has stayed a human task. Evidence-backed VEX is the argument that the assessment can be automated too, and should be, because a human assertion was never going to satisfy a regulator.

What "evidence-backed" actually means

Evidence-backed VEX means the status is the output of a determination, with the artifact attached — not a field someone filled in. The determination runs in two stages, cheap before expensive:

  • Static reachability. Is the vulnerable function present in the shipped product, and can it be reached from an entry point along a path your code actually exercises? This is a call-graph question, and it's cheap to answer at scale.
  • Exploitation proof. For the paths that are reachable — and where the vulnerability is being exploited in the wild — the engine attempts the exploit in your product's context and captures what happens. Success produces a proof artifact. Failure is itself evidence: the vulnerable code is there, reachable, and still could not be triggered.

The order is deliberate. Reachability rules out the large majority of matches cheaply; exploitation, which is the expensive part, only runs where reachability couldn't close the question and the vulnerability is under active exploitation. That two-stage shape is also what keeps the cost bounded — you never brute-force the whole inventory.

How each VEX status earns its evidence

Evidence-backed VEX doesn't change the four statuses. It changes what has to exist before you're allowed to write one.

StatusWhat justifies itEvidence attached
not_affectedThe vulnerable path isn't reachable, or exploitation was attempted and could not trigger it.Reachability trace · exploitation attempt log
affectedThe vulnerable path is reachable and exploitation was demonstrated.Captured exploitation proof
fixedA version with the fix is in the shipped product.SBOM version diff · advisory reference
under_investigationThe determination is not yet resolved — stated honestly, never used to quietly bury a finding.Open determination with reason

VEX also defines standard justification codes for a not_affected — the reason the product is unaffected. Evidence-backed VEX supports the code rather than declaring it:

  • component_not_present — the component isn't actually in this build. (Backed by the SBOM.)
  • vulnerable_code_not_present — the component is present but the vulnerable code isn't in it.
  • vulnerable_code_not_in_execute_path — the code is present but never reached. (Backed by the reachability trace.)
  • vulnerable_code_cannot_be_controlled_by_adversary — reachable, but an attacker can't drive it into the vulnerable state. (Backed by the exploitation attempt.)
  • inline_mitigations_already_exist — a mitigation in your product neutralises it.

Reachability is necessary, not sufficient

It's tempting to stop at reachability. Several good tools flag whether a vulnerable library is actually called, and that alone cuts a lot of noise. But reachability answers a narrower question than it appears to. It tells you the vulnerable code can be called; it doesn't tell you that calling it produces the vulnerable condition.

Plenty of reachable paths are not exploitable. Input validation upstream constrains what reaches the sink. A configuration flag disables the risky feature. The specific version of the component fixed the exploitable branch but not the fingerprint the scanner matched on. In each case, static analysis has to guess — and it tends to guess "reachable, therefore affected," which puts the noise straight back on your queue.

The point

Reachability is the cheap filter; exploitation proof is the verdict. Use the first to avoid running the second where it's pointless. Use the second to resolve the cases the first can only guess at — which are precisely the cases a regulator will ask about.

Why this is the difference that matters for the CRA

Under the EU Cyber Resilience Act, from 11 September 2026 you must report actively exploited vulnerabilities, and you must be able to justify the ones you decided not to report. A VEX document is the natural place that justification lives. But the CRA doesn't want a claim — it wants documented triage decisions with rationale and machine-readable advisories. An unverifiable not_affected doesn't clear that bar.

Evidence-backed VEX changes two things at once. It cuts the reporting load: a CVE proven unreachable carries no reporting obligation, and now that call is backed by evidence rather than nerve. And it makes every remaining decision defensible: when a reasoned request arrives, the reachability trace and exploitation attempt are already attached to the record. You answer "on what basis?" with an artifact, not a name.

That's the practical shape of it on our side too — ingest the SBOM, correlate against the vulnerability sources, run reachability, prove exploitability where it counts, emit the VEX. If you want the mechanics end to end, the how-it-works walkthrough lays out the pipeline; and if the reporting clock is what's keeping you up, the 24 / 72 / 14 reporting guide covers what actually starts it.

Frequently asked

Isn't reachability analysis enough on its own?

Reachability tells you whether the vulnerable code can be called; it does not tell you whether calling it produces the vulnerable condition. A path can be reachable yet unexploitable because of input constraints, existing mitigations or the way the component is configured. Static reachability is the cheap first filter; exploitation proof resolves the cases it can only guess at.

Does the CRA require evidence-backed VEX specifically?

The CRA does not name VEX or any tool. It requires manufacturers to handle vulnerabilities, document their triage decisions with rationale, and be able to justify them to a market-surveillance authority. Evidence-backed VEX is how you meet that bar in a standard, machine-readable form rather than an unverifiable assertion.

What VEX formats does evidence-backed VEX use?

The standard ones: CycloneDX VEX, OpenVEX and the CSAF VEX profile. Evidence-backed VEX changes what sits behind each status, not the format on the wire, so it stays interoperable with any downstream consumer.

What are the not_affected justification codes?

VEX defines standard justifications for a not_affected status: 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. Evidence-backed VEX attaches machine evidence to whichever justification applies.

Design partners

See it on one of your products.

Bring an SBOM. We’ll come back with an evidence-backed VEX where every not_affected carries its proof.