Annotations and VEX

A vulnerability annotation records how a specific (vulnerability, package version) pair affects an app version or an individual container image. Each annotation captures a VEX (Vulnerability Exploitability eXchange) status — whether the package is affected, not affected, fixed, or under investigation — along with the justification, supporting notes, and the actions you intend to take.

Annotations serve two purposes:

  • Internal triage. A not_affected or fixed annotation removes the finding from the default Vulnerabilities view so triage attention stays on the unresolved work. Findings without annotations remain visible; filters can always be adjusted to bring annotated findings back into view.
  • Downstream evidence. Every annotation becomes part of the unified VEX document generated for an app version. Downstream consumers — customers, certifying bodies, deployment gates — see your analysis state directly rather than having to ask.

Annotations in Anchore Enterprise v6 are anchored at the app version and govern findings across every asset attached to that version. A single annotation against (vulnerability, package version) therefore applies whether the affected package was discovered in a container image asset, a filesystem asset, or an externally supplied SBOM asset — you annotate once at the release level rather than once per asset.

The app-version anchor reflects how VEX works in practice: a VEX statement is a release-level claim about how a product is built and used, not a claim about one specific container image. Anchoring the annotation at the version surfaces it consistently across every asset that makes up the release. For the underlying scan surfaces this annotation governs, see Two Evaluation Scopes.

VEX Status

Every annotation carries one of four statuses:

StatusMeaning
not_affectedThe product contains the vulnerable code, but the vulnerability cannot be exploited for various reasons. Additional information should be provided for a detailed explanation.
affectedThe vulnerable package is included in the product and the vulnerability can be exploited. Remediation is typically required.
fixedThe product previously contained the vulnerability, but a patch or remediation has been applied to fix it.
under_investigationThe software supplier is still reviewing their product to determine if it is vulnerable.

Annotations with status not_affected and fixed are hidden from the default Vulnerabilities view at the app-version level as well as the individual image vulnerability view so that triage attention stays on the unresolved findings. Use the VEX Status filter on the Vulnerabilities tab to bring them back into view.

Justification

When status is not_affected, supply a justification that names the reason the vulnerability does not impact the product:

JustificationMeaning
component_not_presentThe vulnerable component is not included in the product.
vulnerable_code_not_presentThe vulnerable component is included, but the vulnerable code is not — usually because of how the component was built or configured.
vulnerable_code_not_in_execute_pathThe vulnerable code is present but is never executed by the product.
vulnerable_code_cannot_be_controlled_by_adversaryThe vulnerable code runs but cannot be reached or influenced by an attacker.
inline_mitigations_already_existThe product includes built-in protections that prevent exploitation and cannot be disabled by the attacker.
fix_not_plannedThe vulnerability impacts the product but no fix is planned. Anchore-specific extension to the CISA VEX values; available via the API.

The first five justifications are CISA’s minimum requirements for a VEX statement and have direct equivalents in OpenVEX and CycloneDX. fix_not_planned is an Anchore extension and is omitted from CycloneDX exports because it has no CycloneDX justification equivalent.

Supporting Fields

Beyond status and justification, every annotation can carry the following free-text fields. Each is optional except where the VEX format requires it:

  • Status notes — additional context about why this status was chosen.
  • Impact statement — required for affected when no justification is supplied; describes how the vulnerability impacts the product.
  • Action statement — for affected annotations: what steps will be taken to remediate the finding.
  • Additional details — any other context that should travel with the annotation.

Anchore Enterprise stamps created_at and updated_at timestamps automatically; the two timestamps correspond to “Analysis First Issued” and “Analysis Last Updated” in the exported VEX document.

Roles and Permissions

Creating, editing, and deleting annotations is restricted by RBAC. The built-in role vuln-annotator-editor carries the relevant permissions:

  • createVulnAnnotation
  • getVulnAnnotation
  • listVulnAnnotations
  • updateVulnAnnotation
  • deleteVulnAnnotation

Any role that grants listImages (such as read-only) can view annotation data and generate VEX exports — see Evidence for the export surfaces.

For details on assigning roles, see Authentication and User Management.


Manage Annotations in the Anchore Enterprise GUI

The Vulnerabilities tab on an app version detail page is the primary interface for annotation work. Each row is one (vulnerability, package) finding, and the Annotated column shows the current VEX status.

Record an Annotation

Open the app version’s Vulnerabilities tab and click the finding you want to annotate to open its detail panel. To set the status alone, use the inline VEX Status dropdown in the panel (None, Not Affected, Affected, Fixed, or Under Investigation). For a full annotation, click Add VEX Annotation (it reads Edit VEX Annotation once an annotation exists) to open the Vulnerability Exploit Statement editor, where you set the Status, a Justification when the status is Not Affected, and any of the optional supporting fields: Status Notes, Impact Statement, Action Statement, and Additional Details. Save stays disabled until a status other than None is selected; click Save to record the annotation.

Once saved, the Annotated column reflects the status across every related finding.

Delete an Annotation

To remove an annotation, open the Edit VEX Annotation editor for an annotated finding and set Status back to None.

A warning confirms that the annotation will be removed and the Save button changes to Delete. Click Delete to clear the annotation.

Filter Annotated Findings

By default the Vulnerabilities tab shows unannotated findings plus those marked Affected or Under Investigation, so unresolved work stays at the top; findings marked Not Affected or Fixed are hidden. Use the VEX Status filter to add Not Affected or Fixed back into view, which is useful when reviewing the triage backlog or preparing a VEX document for export.


Manage Annotations with AnchoreCTL

Annotation management is exposed under anchorectl app version vex. Every command requires the parent app via --app.

Add an Annotation

The package identity (--pkg-name, --pkg-type, --pkg-version) plus --vuln-id together uniquely identify the (vulnerability, package) pair the annotation applies to:

anchorectl app version vex add 1.4.0 \
  --app my-service \
  --vuln-id CVE-2024-3094 \
  --pkg-name xz-utils \
  --pkg-type deb \
  --pkg-version 5.6.0-0.2 \
  --status not_affected \
  --justification vulnerable_code_not_in_execute_path \
  --status-notes "xz-utils is bundled but the affected SSH path is not used by this service."

A second annotation for the same (vuln_id, package_name, package_version, package_type) tuple is rejected with a 409 conflict — update the existing annotation instead.

List Annotations for an App Version

anchorectl app version vex list 1.4.0 --app my-service

The default table output covers status, justification, package identity, and the annotation UUID. Use -o json for the full per-annotation record including all supporting fields.

Update an Annotation

Annotations are updated by UUID (the id returned at creation, or the id field from list):

anchorectl app version vex update 943629bb-83ab-0f2c-3326-f0c011ab16cf \
  --app my-service \
  --version 1.4.0 \
  --status fixed \
  --status-notes "Upgraded to xz-utils 5.6.2-1 in the 1.4.0 release."

Only the fields supplied on the command line are changed; omitted fields keep their existing values.

Delete an Annotation

anchorectl app version vex delete 943629bb-83ab-0f2c-3326-f0c011ab16cf \
  --app my-service \
  --version 1.4.0

Deleting an annotation does not affect the underlying vulnerability finding — the finding reappears in the default Vulnerabilities view because nothing is filtering it out anymore.

Export VEX for an App Version

anchorectl app version export vex produces a CycloneDX VEX document for the app version. The export runs as a server-side job; AnchoreCTL waits for completion and writes the result to a file or stdout:

anchorectl app version export vex 1.4.0 \
  --app my-service \
  --format cyclonedx-json \
  --file my-service-1.4.0-vex.json

Manage Annotations with the API

Annotation endpoints live under /apps/{app_id}/versions/{version_id}/vulnerability-annotations. The full request and response schemas are in the API browser; search for the App Version Vulnerability Annotations tag.

Key endpoints:

MethodPathPurpose
POST/apps/{app_id}/versions/{version_id}/vulnerability-annotationsCreate an annotation for a (vulnerability, package) pair
GET/apps/{app_id}/versions/{version_id}/vulnerability-annotationsList annotations for the version
GET/apps/{app_id}/versions/{version_id}/vulnerability-annotations/{vulnerability_annotation_id}Retrieve a single annotation by UUID
PATCH/apps/{app_id}/versions/{version_id}/vulnerability-annotations/{vulnerability_annotation_id}Update fields on an existing annotation
DELETE/apps/{app_id}/versions/{version_id}/vulnerability-annotations/{vulnerability_annotation_id}Remove an annotation

A few conventions worth knowing as you call these endpoints:

  • The uniqueness constraint is (account, app, version, vulnerability_id, package_name, package_version, package_type). Creating a second annotation for the same tuple returns 409.
  • PATCH accepts a partial body; omitted fields are left untouched. Explicit null is rejected for the status field — drop the key to leave the status unchanged.
  • VEX exports are produced by the App Jobs export endpoints rather than the annotation endpoints directly — see Evidence.
  • Cross-version annotation searches — finding every vulnerability annotated as not_affected across an account, for example — are not yet exposed through a programmatic surface. App-version search and reporting is on the roadmap; see Search for the current state and the per-version data sources available in the meantime.

Policy Gating by Annotation Status

The package trigger on the vulnerabilities compliance gate exposes two parameters that filter findings by annotation state — missing annotation and annotation status. These parameters are available only on rule sets whose artifact type is image; SBOM/app-version rule sets do not currently expose annotation-status filtering at the policy layer. App-version-scoped annotation filtering through search or reports is on the roadmap — see Search for the current state.

For parameter definitions, see Vulnerabilities Gate.

Last modified June 16, 2026