The analysis your supplier already did
A supplier ships you a component. Your scanner finds forty CVEs in it. Thirty-one of them are in code paths their build never compiles, and they know this, because somebody on their side spent a week working it out.
So they tell you. Sometimes in a PDF, sometimes in a spreadsheet, increasingly in a machine-readable document, a VEX file listing each vulnerability and whether it affects the product.
And then the interesting part. You take their thirty-one, and you type them into your own suppression config, because that is where your pipeline looks.
What you just lost#
Not the week. The week was theirs and they already spent it.
What you lost is the answer to the only question anybody asks about a suppressed finding. Not did the scanner run. It ran, that is why you have forty findings. The question is who decided this one was acceptable, and when.
Before you retyped it, that had a good answer: your supplier, in a document, on a date, with a technical justification and somebody's name on it. After, it has a worse one: you, in a config file, with a reason that reads like your reason because it is in your file, under your commit, signed by whoever opened the pull request.
The next person to audit that finding asks your team to defend an analysis your team did not do.
The document was already the right shape#
A VEX statement is a claim rather than a suppression rule, and a claim has parts a rule does not:
{
"vulnerability": { "name": "CVE-2016-2781" },
"products": [{
"@id": "pkg:oci/example/base-python",
"subcomponents": [{ "@id": "pkg:deb/debian/coreutils@9.1-1" }]
}],
"status": "not_affected",
"justification": "vulnerable_code_not_in_execute_path",
"impact_statement": "chroot(1) is only exploitable when invoked by a privileged process that then drops privileges. Nothing in this image runs it, and the image runs as an unprivileged user."
}
An author, a date, a vocabulary term a machine can act on, and prose a person can argue with. A package identifier precise enough to match one library inside one image.
Copying that into a suppression keeps the prose and throws away everything else.
So read it instead#
Point at the document:
components:
- name: payments-api
images:
- image: registry.example.com/acme/api:1.4.0
vex:
- path: vendor/acme-api.openvex.json
Or at a URL they publish, or a path inside a repository of theirs, cloned with whatever credentials git already has on the machine, so a private supplier repository works without a token in your descriptor.
The findings they excused stop counting against your gate, exactly as an exclusion would. What is different is the record:
1 finding excused by a supplier's VEX · 1 asserted by Example Base Images <security@example.com>That line is the whole argument. Every finding it covers carries the author, the document it came
from, and the date the claim was asserted, in the terminal, in report.json, and in the SARIF
property bag your platform reads. A year-old not_affected about a package that has moved on reads
as old, rather than as current.
What a supplier is not allowed to do#
This is where consuming somebody else's claims stops being obviously a good idea, so it is worth being precise about the limits.
They cannot turn off a finding by telling you it is bad. Only not_affected and fixed excuse
anything. A supplier statement of affected is recorded and reported and changes nothing, which
sounds obvious until you consider that a system treating every statement alike would let a vendor's
honesty about their own exposure quietly reduce your finding count.
They cannot overrule you. Where your own exclusion already covers a finding, your reason stands. Their claim is evidence; it is not an override. The reason whose author you can walk down the hall and ask is the more useful one to keep.
They cannot reach past their own component. A document declared on one component applies to that component's findings. One vendor's assurance excusing something in a service they have never seen is the failure this design exists to prevent.
They cannot talk you into the safer of two stories. If two statements disagree about the same
package, the one conceding more exposure wins. Reporting affected for something that turns out
to be fine costs somebody an afternoon. The other direction tells a customer they are safe when
they are not.
And they cannot do nothing quietly. A statement that matches no finding is reported, because a document that excused nothing looks exactly like one that is working. Usually it means your scanner and their tooling name the same package differently, which is worth knowing before you assume you are covered.
The honest state of VEX#
VEX is not a solved technology, and it would be easy to write this post as though it were.
The OpenSSF's own survey of the field
puts it bluntly: VEX "feels more like a promise than a practice". There is no common way to
discover a supplier's document. Signing and verification conventions are unsettled. Different tools
identify packages by different schemes, so a correct statement can match nothing at all. Some
vendors publish meticulous analysis; others publish bulk not_affected with no supporting evidence,
which is worth exactly what it costs to produce.
All true. Here is why it does not change the conclusion.
The consuming side is where the leverage is, and it is the half nobody built. Producing VEX is well served, several major vendors publish it today. What is missing is the other end: the leading open-source SBOM platform has an open defect, filed in April 2025, for ignoring external VEX documents during ingestion, with a workaround involving uploading a document, downloading it back, editing it, and uploading it again.
A bad claim is visible rather than laundered. The distribution and quality problems are real,
and they are arguments for attribution, not against consumption. A vendor's unsupported bulk
not_affected copied into your config is invisible. The same claim read as a claim has their name
on every finding it touched, and a reviewer can weigh it.
And the pressure is arriving on a date. Under the EU Cyber Resilience Act, 24-hour vulnerability reporting begins on 11 September 2026, with full obligations in December 2027. ENISA's 2026 survey of SBOM adoption found that 76% of organizations rate receiving exploitability claims from suppliers as critical or important, and that the delivery they want is automatic or through an API, not an email with an attachment. The suppliers who have not been publishing are about to start, because their customers are contractually asking.
The case that does not wait for the ecosystem#
There is one arrangement where none of the adoption problems apply, and it is more common than the vendor case: your suppliers are other teams in your own company.
A platform team publishes a base image. Twelve product teams consume it. The platform team already knows which CVEs in that image are reachable, and if they run a scanner that produces VEX, they already have the document. Nobody is waiting on an industry convention, because both ends are yours.
config:
vexSources:
- url: https://platform.internal/vex/current.openvex.json
Said once, applied to every component. The platform team's analysis lands in twelve pipelines with their name on it, and when somebody asks why a finding stopped counting in the payments service, the answer names the team who assessed it rather than the person who happened to edit the config.
What this does not do#
It does not decide whether a claim is true. Draugr records whose it was and when they made it; the judgement stays with you, which is the only place it can honestly sit. Naming a source is the decision to accept it.
And it is not a substitute for reading what you accepted. A supplier's document is a description of their product as they understand it on the day they wrote it. Everything above is machinery for keeping that fact attached to the finding, not for making it go away.
The scanner found forty. Somebody did the work on thirty-one of them. The least you can do is keep their name on it.