VEX — OASIS CSAF 2.1 Vulnerability Exploitability eXchange

VEX (Vulnerability Exploitability eXchange) statement builder per OASIS CSAF 2.1 §4.4 (CSAF VEX profile). Operators ship a vex.cdx.json alongside sbom.cdx.json declaring per-vulnerability exploitability state for the framework's component set. Status vocabulary follows the CSAF VEX profile §4.4 restriction (a strict subset of the full CSAF 2.1 §3.2.3.13 product_status vocabulary):

"fixed" — framework included the vulnerable component previously; the cited version ships the fix "known_affected" — framework includes and uses the vulnerable component; remediation required "known_not_affected" — framework does not include / does not use the vulnerable component "under_investigation" — disclosure is being evaluated

Justifications (when status=known_not_affected): component_not_present, vulnerable_code_not_present, vulnerable_code_not_in_execute_path, vulnerable_code_cannot_be_controlled_by_adversary, inline_mitigations_already_exist (CSAF 2.1 §3.2.2.7).

b.vex.statement({...}) produces a single VEX vulnerability record. b.vex.document({...}) assembles a complete CSAF 2.1 document with the framework's distributor metadata + an auto-emitted product_tree.full_product_names resolving every product_ids reference used by the statements (CSAF 2.1 §3.1). b.vex.serialize round-trips to canonical JSON (RFC 8785 / sorted keys) for signing.

Why the framework ships VEX: operators consuming the framework's VEX populate their own organisational VEX without re-auditing each framework dependency. Downstream consumers (Dependency-Track, csaf-validator-service, FIRST.org CSAF) reject malformed docs; shipping a spec-conformant doc is the cost of admission.

b.vex.statement(opts) #

stable0.9.6
{
  cveId:           string,    // CVE-YYYY-NNNN
  cweId:           string,    // CWE-NNN (emitted as cwes[0] per CSAF §3.2.3.4)
  cweName:         string,    // human-readable CWE name (e.g. "Cross-site Scripting"); when omitted, cwes[].name is omitted (avoids CWE-ID-as-name antipattern flagged by csaf-validator)
  ids:             object[],  // [{ systemName, text }] non-CVE tracking ids
  title:           string,    // human-readable vulnerability title
  status:          string,    // one of STATUS_VALUES (VEX profile subset)
  productIds:      string[],  // CSAF product identifiers
  justification:   string,    // required when status=known_not_affected
  impactStatement: string,    // operator-readable impact / mitigation note (shorthand for notes[{category:"details",...}])
  notes:           object[],  // [{ category, text, title? }] full CSAF notes channel (CSAF §3.2.3.7)
  references:      array,     // [string] or [{ url, summary?, category? }] — CSAF §3.2.3.10
  firstReleased:   string,    // ISO 8601 timestamp
  lastUpdated:     string,    // ISO 8601 timestamp
}

Build a single CSAF 2.1 VEX vulnerability record. Returns an object shaped per CSAF 2.1 §3.2.3 vulnerability schema with the supplied CVE ID + product status + (when applicable) justification + impact statement.

Required: a vulnerability identity — cveId (CSAF §3.2.3.2) and/or ids (CSAF §3.2.3.5 — array of { systemName, text } non-CVE tracking identifiers for advisories without an assigned CVE). A cweId alone is NOT a valid CSAF vulnerability identity (CWE is a weakness classification, not a per-vulnerability id); supply ids alongside cweId when issuing a non-CVE statement. Also required: status (one of STATUS_VALUES — CSAF VEX profile §4.4 subset), productIds (array of product identifiers the statement applies to).

When status === "known_not_affected", justification is required per CSAF 2.1 §3.2.3.13.

b.vex.statement({
  cveId:           "CVE-2024-21505",
  title:           "axios SSRF",
  status:          "known_not_affected",
  productIds:      ["@blamejs/core"],
  justification:   "component_not_present",
  impactStatement: "blamejs ships zero npm runtime deps; axios is never imported.",
});

b.vex.document(opts) #

stable0.9.6
{
  documentId:        string,            // unique per-publication id (e.g. "blamejs-vex-2026-05-12")
  title:              string,           // document title
  publisher:          { name, namespace, contactDetails? },
  tlp:                string,           // one of TLP_LABELS; default "CLEAR"
  distributionText:   string,           // overrides TLP_DEFAULT_TEXTS[tlp]; required when TLP RED or AMBER+STRICT and operator wants non-default prose
  lang:               string,           // BCP 47 language tag (CSAF §3.2.1.13); default "en"
  trackingStatus:     string,           // CSAF §3.2.1.6 tracking.status — "draft" | "interim" | "final"; default "final"
  productTreeNames:   object,           // optional { "": "" } — when omitted, productId doubles as display name
  statements:         object[],         // array of b.vex.statement output
  distributor:        { ... },          // optional CSAF distributor block
  trackingId:         string,           // CSAF tracking id (e.g. version-pinned)
  trackingVersion:    string,           // semver
  currentReleaseDate: string,           // ISO 8601 timestamp
  initialReleaseDate: string,           // ISO 8601 timestamp
}

Assemble a complete CSAF 2.1 VEX document with the supplied vulnerability statements + framework distributor metadata. The document auto-emits product_tree.full_product_names resolving every product_ids reference used by the statements (CSAF 2.1 §3.1) so the document is self-contained — spec-conformant VEX validators (csaf-validator-service, Dependency-Track) require every product_ids reference to resolve against the document's own product_tree.

var doc = b.vex.document({
  documentId:         "blamejs-vex-2026-05-12",
  title:              "blamejs framework VEX disclosures",
  publisher:          { name: "blamejs", namespace: "https://blamejs.com/" },
  trackingId:         "blamejs-vex-2026-05-12-001",
  trackingVersion:    "1.0.0",
  currentReleaseDate: "2026-05-12T00:00:00Z",
  initialReleaseDate: "2026-05-12T00:00:00Z",
  statements:         [
    b.vex.statement({ cveId: "CVE-2024-21505", status: "known_not_affected", productIds: ["@blamejs/core"], justification: "component_not_present" }),
  ],
});

b.vex.serialize(doc) #

stable0.9.6

Serialize a VEX document to canonical JSON suitable for shipping as vex.cdx.json or signing. Sorted-keys form so byte-equality is stable across regenerations (matches the framework's b.canonicalJson discipline).

var json = b.vex.serialize(doc);
fs.writeFileSync("vex.cdx.json", json);

Last updated 2026-08-08T16:39:49.652Z by seeder.