Safeguard
Supply Chain•

Which VEX justification fits a container finding that does not apply?

OpenVEX has five fixed not_affected justifications. Here is how to pick the right one for a container finding and what evidence each one needs.

Safeguard Security Team
7 min read

When a container scan reports a vulnerability that does not apply to you, OpenVEX gives you five fixed justification labels for a not_affected statement. They range from the component not being present to built-in mitigations. Choose the label your evidence supports, attach that evidence, and give the statement a review date.

What a VEX statement is

VEX stands for Vulnerability Exploitability eXchange. A VEX statement says whether a product is affected by a vulnerability. The OpenVEX specification defines status values including not_affected, affected, fixed and under_investigation. It says that for not_affected, a statement must include either a status justification or an impact statement explaining why the product is not affected.

That rule is the useful part for container teams. A scanner lists everything installed. VEX is how you record, in a standard form, that some of those items are harmless in your context, and why.

The five justifications in plain words

LabelPlain meaningTypical container case
component_not_presentThe component is not in the productA package was removed in a later build step, so the finding is stale
vulnerable_code_not_presentThe component is there but the vulnerable code is notThe library was built without the affected module
vulnerable_code_not_in_execute_pathThe vulnerable code exists but cannot run as the product uses itA function in a bundled library is never called
vulnerable_code_cannot_be_controlled_by_adversaryAn attacker cannot influence the vulnerable codeThe affected input comes only from trusted internal configuration
inline_mitigations_already_existBuilt-in protections prevent exploitationA setting or feature in the product blocks the attack path

The OpenVEX text describes the second as the case where the vulnerable component is included but the vulnerable code is not, for example when the source was configured or built in a way that excluded it. It describes the third as code that cannot be executed as the product uses it. For the fourth, it warns that the justification can be difficult to prove conclusively. For the fifth, it says the protections cannot be subverted.

How to choose

Ask three questions in order.

  1. Is the component actually in the final image? If not, the label is component_not_present. Verify with the package list of the exact digest.
  2. If it is, is the vulnerable code in the build? If the affected module was compiled out or a feature flag removed it, use vulnerable_code_not_present.
  3. If the code is present, can it run, and can an attacker reach it? Use not_in_execute_path when it never runs, cannot_be_controlled_by_adversary when it runs but inputs are trusted, and inline_mitigations when something blocks the attack.

Work from the strongest, easiest to prove claim to the weakest. A claim you cannot prove should not be made. If you are not sure, the honest status is under_investigation, which the specification describes as meaning it is not yet known whether the versions are affected, with updates to follow.

A worked example

A scan of an image reports a vulnerability in an image processing library that a web framework bundles. The team investigates.

  • The package is in the image, so component_not_present is out.
  • The vulnerability is in a decoder for one file format. The team checks the build configuration and finds that decoder is compiled in. So vulnerable_code_not_present is out.
  • The service never accepts uploaded images and never calls the decoding functions. Static analysis and a code search agree. This supports vulnerable_code_not_in_execute_path.

The team records the statement with that label, the evidence (the search result and the code review), the image digest and a review date. If a later feature adds image uploads, the statement must be revisited, so the team sets an expiry and links it to the feature's design review.

Step by step: write a good statement

  1. Name the product by image digest, not just by tag.
  2. Name the vulnerability by its identifier.
  3. Pick the status. For not_affected, pick one justification label.
  4. Add a short impact statement in plain words for the reader.
  5. Attach or link the evidence.
  6. Add an expiry or a trigger for review.
  7. Have someone else review it.
  8. Publish it where your customers or your own tools can read it.

Evidence to keep for each label

LabelEvidence worth keeping
component_not_presentPackage list of the exact digest showing the component absent
vulnerable_code_not_presentBuild configuration or a listing showing the affected module was excluded
vulnerable_code_not_in_execute_pathCode search results, call graph or reachability output, plus a reviewer note
vulnerable_code_cannot_be_controlled_by_adversaryData flow notes showing the input source is trusted
inline_mitigations_already_existThe setting or feature that blocks the path, and a test showing it works

Keep the evidence next to the statement, with the image digest and the date. If a customer or auditor asks months later, you should be able to answer in minutes, not rebuild the investigation.

How VEX fits into a container workflow

A practical flow looks like this. The scan runs and produces findings. Triage sorts them into fix now, fix later and does not apply. For the third group, an engineer writes a VEX statement with a label and evidence, and a second person reviews it. The statement is attached to the image digest, so it stays with the artifact. When the image is rebuilt, a new scan runs, and the statements are checked again: any statement whose conditions changed is reopened.

Two details help in practice. First, tie statements to a digest or a version range you actually checked, not to a product name in general. Second, keep a short list of who may approve each label, since the reachability based labels carry more risk than component_not_present.

What not to do

  • Do not use a justification you cannot back up. A wrong VEX statement misleads customers.
  • Do not apply a statement to all images by CVE alone. It applies to products and versions you checked.
  • Do not treat VEX as a replacement for scanning. It annotates scan results. See does VEX replace vulnerability scanning.
  • Do not let statements live forever. Code changes can make them false.

Try it yourself

Click through it at your own pace, or open it full screen.

Try to decide, for the finding shown, which of the three questions above it answers, and what evidence you would attach.

Where Safeguard fits

Safeguard offers reachability analysis, which can help you gather evidence for the execute path question, and it keeps findings and decisions with their history. You can try a free scan at gold.safeguard.sh/scan.

Quick check

Do I need a justification for every not_affected statement?

Per the OpenVEX specification, a not_affected statement must include either a status justification or an impact statement that explains why.

Which justification is the easiest to prove?

component_not_present, because you can check the package list of the exact image digest. The arguments about reachability and attacker control take more evidence.

When should I use under_investigation?

When you do not yet know whether the product is affected. The specification expects a later update when you do.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.