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) #
{
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) #
{
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) #
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.