Yes. The same component can be exploitable in one deployment and harmless in another, because configuration, build options, exposure and mitigations differ. Record the decision per deployment, using a standard status and justification, so the answer is evidence and not an opinion.
Why the answer can differ
A vulnerable function may be disabled by configuration in one service and enabled in another. One build may exclude the vulnerable module while another includes it. One deployment may sit behind an input filter that blocks the trigger, and another may accept raw input from the internet.
If you give a single answer for the component, you will be wrong somewhere, either by wasting effort or by missing real exposure.
The vocabulary
The OpenVEX specification defines four statuses: not_affected, affected, fixed and under_investigation. For not_affected, a statement needs a justification or an impact statement. The justifications it lists are:
| Justification | Meaning |
|---|---|
| component_not_present | The component is not included |
| vulnerable_code_not_present | Included, but the vulnerable code was excluded by configuration or build |
| vulnerable_code_not_in_execute_path | The vulnerable code is never executed |
| vulnerable_code_cannot_be_controlled_by_adversary | An attacker cannot control the vulnerable code |
| inline_mitigations_already_exist | Built in protections prevent exploitation |
The spec discourages free text impact statements because they hinder automation, so prefer the fixed list.
Identify the product precisely
A statement must name at least one product. OpenVEX supports identifiers such as package URLs, and hashes such as sha-256, so you can name a specific artifact by digest. That is how you make one statement for the production image and a different one for the test image, even when both come from one repository.
A working method
- Start with the finding key: advisory plus component and version.
- Take each artifact that contains it.
- Check evidence per artifact: build file, configuration, reachability result.
- Pick a status and justification. If you cannot support not_affected, use affected or under_investigation.
- Record who decided and when.
- Re-check on change. A new build or configuration can invalidate the statement.
Be careful with mitigations
An external control, such as a network filter, is a mitigation for exposure, not proof the code is absent. The list above treats mitigations that are built in and cannot be disabled by users as a justification. A filter someone can reconfigure is weaker, so record it as a compensating control unless you have strong evidence.
Try it yourself
Open the demo and see how an exploitability check combines signals about a finding. Look for what evidence it uses before it gives an answer.
Click through it at your own pace, or open it full screen.
A worked example
A parsing library has an advisory that only matters when a certain feature is switched on. Service A enables it, so its statement is affected, and it gets a fix ticket. Service B ships the same library but never turns the feature on, and its build excludes the optional module, so the statement is not_affected with vulnerable_code_not_present. Service C is still being checked and stays under_investigation until someone reads its configuration. Three statements, three outcomes, one component.
Quick check
Do I need one VEX document per environment?
Not necessarily. One document can hold several statements, each naming a different product or artifact.
Is not_affected permanent?
No. Revisit it when the build, configuration or component version changes.
Safeguard's reachability analysis supports this kind of evidence, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.