Skip to content
compliance-owner

Suppress a false match with a VEX statement

Was this page helpful?

A VEX (Vulnerability Exploitability eXchange) statement lets you tell Declara that your own assessment already covers a match — so it doesn't need to interrupt anyone as a new alert.

Which statuses suppress

  • not_affected — suppresses.
  • fixed — suppresses.
  • affected — does not suppress. You've confirmed exploitability; the match should alert.
  • under_investigation — does not suppress. An assessment in progress can't be used to quiet a clock before it's finished.

Before you start

You need sbom.upload-adjacent access to submit VEX documents for a product (the same permission tier as uploading an SBOM), and the statement needs to name the advisory and either the specific component or the whole product.

Steps

  1. Prepare a VEX document — either an OpenVEX document or a CycloneDX BOM carrying a vulnerabilities array with analysis blocks. Both are accepted.

    Most people hand-write the OpenVEX form; it is short. This is a complete document saying that one advisory does not reach your product, and it is enough to copy and edit:

    {
      "@context": "https://openvex.dev/ns/v0.2.0",
      "@id": "https://acme.example/vex/2026-0001",
      "author": "Acme Security <security@acme.example>",
      "timestamp": "2026-01-15T09:00:00Z",
      "version": 1,
      "statements": [
        {
          "vulnerability": { "name": "CVE-2025-12345" },
          "products": [{ "@id": "pkg:npm/lodash@4.17.20" }],
          "status": "not_affected",
          "justification": "vulnerable_code_not_in_execute_path",
          "impact_statement": "The parsing entry point the advisory describes is never called."
        }
      ]
    }

    @id, author and timestamp identify the document; nothing checks them, but they are what makes the statement evidence rather than a note. The field that decides whether anything happens is products[].@id: it must be the package URL exactly as the inventory shows it on the product's page. A name that is not a valid purl is dropped, and the statement then applies to the whole product rather than to that component — which suppresses more than you meant. Omit products deliberately if whole-product scope is what you want.

    If you would rather not write JSON, vexctl is the OpenSSF tool that generates and merges these documents.

  2. Upload it against the relevant product, in Exploitability statements on that product's page. That card appears once an SBOM has been uploaded — before there is an inventory there are no matches for a statement to suppress. SBOMs themselves go in Upload an SBOM, further up the same page.

  3. Declara reads the statement's status, justification, and detail, and matches it to the advisory and component (or whole-product scope) it names.

  4. On the next match run, any not_affected or fixed statement suppresses the corresponding match before an alert is raised.

What you should see

A suppressed match shows in your inventory as suppressed by VEX, with the statement's justification attached — it never reaches your Alerts list, and nobody is notified.

If you filed a VEX statement expecting it to close an existing alert and it didn't, see Troubleshooting — the fix is to close the alert through triage, not to resubmit the VEX statement.

Export your own

The same card offers your product's VEX the other way: a document built from your triage decisions and the statements imported here, for your customers' scanners. See Export a product's VEX.