Safeguard
Supply Chain Security•

Write Your First OpenVEX Statement With vexctl

What a VEX statement says, the four status values, and the five justifications, shown by generating a real OpenVEX document with vexctl v0.4.4.

Safeguard Security Team
3 min read

A VEX statement is a short claim from a supplier: for this product and this vulnerability, here is the status. It is how you tell customers that an advisory in their scanner does not apply to you. On 15 October 2026 the GitHub advisory for @opennextjs/cloudflare named CVE-2026-100409, which applies only when cache interception is enabled, a good case for a "not affected" statement.

We generated one with vexctl v0.4.4, the OpenVEX project's command line tool, released on 16 June 2026.

What's affected

The statement below concerns @opennextjs/cloudflare 1.20.1, which the advisory lists as vulnerable because the fix landed in 1.20.2. It would be true only for an application that never enables enableCacheInterception. Treat it as an illustration of the format, not a statement about any real product.

The OpenVEX spec defines four status values: not_affected, affected, fixed, under_investigation. A not_affected statement must carry either a justification or an impact statement. The spec gives five machine readable justifications:

  • component_not_present
  • vulnerable_code_not_present
  • vulnerable_code_not_in_execute_path
  • vulnerable_code_cannot_be_controlled_by_adversary
  • inline_mitigations_already_exist

What to do now

  1. Install vexctl: go install github.com/openvex/vexctl@v0.4.4.
  2. Create a statement. The command shape comes from the vexctl README:
vexctl create --product="pkg:npm/%40opennextjs/cloudflare@1.20.1" \
              --vuln="CVE-2026-100409" \
              --status="not_affected" \
              --justification="vulnerable_code_not_in_execute_path"
  1. Read the output. Our run produced a document with these key fields:
{
  "@context": "https://openvex.dev/ns/v0.2.0",
  "author": "Unknown Author",
  "version": 1,
  "statements": [
    {
      "vulnerability": { "name": "CVE-2026-100409" },
      "products": [ { "@id": "pkg:npm/%40opennextjs/cloudflare@1.20.1" } ],
      "status": "not_affected",
      "justification": "vulnerable_code_not_in_execute_path"
    }
  ]
}
  1. Set the author with --author. The default is "Unknown Author", which no consumer should accept.
  2. Try leaving out the justification. vexctl refuses: invalid statement: either justification or impact statement must be defined when using status "not_affected".
  3. Sign or publish the document alongside your SBOM, and update it when status changes to fixed.

Try it yourself

Take one advisory from your own backlog that you believe does not apply. Pick the justification from the five above that matches the reason, then write the command. If none fits, the advisory probably does apply.

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

Quick check

Which statuses require no justification?

Only not_affected needs a justification or impact statement. For affected, the spec says the statement should describe actions to remediate or mitigate.

Sources

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.