{"$schema":"https://docs.oasis-open.org/csaf/csaf/v2.1/schema/csaf.json","document":{"category":"csaf_informational_advisory","csaf_version":"2.1","distribution":{"tlp":{"label":"CLEAR"}},"lang":"en","notes":[{"category":"summary","text":"This advisory records the introduction of the `dashboard-branding` CSAF 2.1 vendor extension across the ndaal CSAF Trusted Provider feed.  The extension carries operator-facing dashboard labels for the nvulnlookup `/dashboards/<slug>` web UI and is compliant with the OASIS CSAF 2.1 Draft 2+ vendor-extension mechanism (`document.x_extensions[]` array).\n\nThree concrete artefacts ship together in this enrichment:\n\n  1. NEW extension content schema at\n     `csaf/extensions/dashboard-branding_1.0.0.json` — JSON Schema\n     describing the extension's payload object (publisher_brand,\n     dashboard_short_name).  Self-referencing $id is\n     `https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json`\n     (SemVer-suffixed per the CSAF 2.1 extension URL regex).\n\n  2. NEW extension metadata file at\n     `csaf/extensions/dashboard-branding-metadata_1.0.0.json`\n     declaring `valid_locations: [{ path: '/document/x_extensions', max_occurrence: 1 }]`\n     and `requirement: 'Optional'` so a CSAF consumer that does\n     not understand the extension can safely ignore it.\n\n  3. ENRICHMENT of all 41 existing 2026 advisories (`ndaal-sa-2026-001`\n     through `ndaal-sa-2026-041`) with one `document.x_extensions[]`\n     element pointing at the new schema URL.  The element carries\n     `publisher_brand: 'ndaal Advisories Database'` (rendered in\n     the dashboard page <h1>) and `dashboard_short_name: 'ndaal'`\n     (rendered in the navbar dropdown / breadcrumbs).  Each\n     advisory's three sidecar files (`*.sha-256`, `*.sha-512`,\n     `*.sha3-512`) were regenerated after the JSON edit.\n\nThe `csaf/provider-metadata.json` file additionally received\n`publisher.x_publisher_brand` and `publisher.x_dashboard_short_name`\nfields under `document.publisher.*` (CSAF 2.1 `provider.json`\nschema does NOT set `additionalProperties: false` on the\npublisher object, so the extension is spec-compliant at the\nprovider level).\n\nNet effect on a v0.1.43+ deployment: when a downstream operator\nmirrors the ndaal feed and feeds it into the nvulnlookup web UI,\nthe dashboard pages now render the operator-friendly brand label\n('ndaal Advisories Database') in the page header and the short\nlabel ('ndaal') in the navbar — without any code changes on the\nconsumer side, because the labels travel with the advisory.\n\nThis advisory itself carries the same `document.x_extensions[]`\nelement for consistency with the 41 enriched advisories."},{"category":"description","text":"## Background — CSAF 2.1 vendor-extension mechanism\n\nCSAF 2.1 Draft 2 added a first-class extension hook at\n`document.x_extensions: [object]`.  The schema definition\n(csaf.json, OASIS open repository) declares it as an array of\nuntyped objects with `additionalProperties: true`, so any\nextension that follows the documented x-extension contract is\nlegal under the strict 2.1 schema.  An extension is described\nby two side-files:\n\n  * `extension-metaschema.json` — defines the SHAPE of an\n    extension (used by the extension content schema as $schema).\n  * `extension-metadata.json`   — defines WHERE the extension\n    may appear (`valid_locations`) and HOW IMPORTANT it is\n    (`requirement: 'Required' | 'Optional'`).\n\nA producer publishes (a) the extension content schema and\n(b) the extension metadata, both at stable URLs, and embeds\nthe content schema by URL into each emitting advisory's\n`document.x_extensions[]` entry via `$schema`.\n\n## What this enrichment ships\n\n  * NEW FILE\n    `csaf/extensions/dashboard-branding_1.0.0.json`\n    + `$schema: https://docs.oasis-open.org/csaf/csaf/v2.1/schema/extension-metaschema.json`\n    + `$id:    https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json`\n    + required: [$schema, category, critical, content]\n    + properties:\n        $schema  → const(self URL)\n        category → const('informational')\n        critical → const(false)\n        content  → object{publisher_brand, dashboard_short_name}\n    + additionalProperties: false everywhere — this extension is\n      a fixed shape, not a free-form metadata bag.\n\n  * NEW FILE\n    `csaf/extensions/dashboard-branding-metadata_1.0.0.json`\n    + `$schema: https://docs.oasis-open.org/csaf/csaf/v2.1/schema/extension-metadata.json`\n    + `extension_schema: https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json`\n    + `requirement: 'Optional'`\n    + `valid_locations: [{ path: '/document/x_extensions', max_occurrence: 1 }]`\n    + `last_updated: 2026-05-09T08:00:00.000Z`\n\n  * EDIT\n    `csaf/provider-metadata.json`\n    + `publisher.x_publisher_brand:    'ndaal Advisories Database'`\n    + `publisher.x_dashboard_short_name: 'ndaal'`\n    + Both fields are accepted by the OASIS provider.json schema\n      because the publisher object does NOT carry\n      `additionalProperties: false` in CSAF 2.1.\n\n  * ENRICHMENT — for each of the 41 existing 2026 advisories\n    (`csaf/2026/<NNN>/ndaal-sa-2026-<NNN>.json`, NNN in 001..041),\n    one `document.x_extensions[]` element added:\n\n      \"x_extensions\": [\n          {\n              \"$schema\": \"https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json\",\n              \"category\": \"informational\",\n              \"critical\": false,\n              \"content\": {\n                  \"publisher_brand\": \"ndaal Advisories Database\",\n                  \"dashboard_short_name\": \"ndaal\"\n              }\n          }\n      ]\n\n    Re-runnable enrichment script:\n      `csaf/enrich_publisher_metadata.sh` — idempotent on\n      already-enriched JSON; sidecars regenerated only when\n      JSON bytes change OR a sidecar is empty.\n\n    Companion revert script:\n      `csaf/revert_publisher_x_extensions.sh` — restores any\n      previous behaviour where the extension was placed under\n      `document.publisher.*` (a path the strict CSAF 2.1\n      csaf.json rejects with additionalProperties:false).\n\n  * REGENERATED SIDECARS — 123 files in total\n    (41 advisories x 3 hash families per\n     advisory: SHA-256 / SHA-512 / SHA3-512).\n    Generation pattern, per `claude.md` policy:\n        shasum -a 256 <f>  > <f>.sha-256\n        shasum -a 512 <f>  > <f>.sha-512\n        sha3sum -a 512 <f> > <f>.sha3-512\n\n## Rationale — why ship this as an extension and not in a\n## proprietary publisher.x_* field\n\nA prior iteration of this branding enrichment (squashed pre\nrelease) placed the two labels under `document.publisher.x_publisher_brand`\nand `document.publisher.x_dashboard_short_name`.  That failed\nstrict CSAF 2.1 csaf.json validation because the `publisher`\nobject in csaf.json is declared with `additionalProperties:\nfalse`.  Switching the carrier to the official 2.1 Draft 2+\nextension mechanism (`document.x_extensions[]`) keeps the same\noperator-facing semantics while passing the OASIS schema\nunchanged.\n\n## Validator behaviour\n\nThe Rust `csaf-validator 0.4.1` (used in CI as a double-check\nlayer) currently reports the same set of pre-existing schema\nbugs against the enriched advisories that it reported against\nthe pre-enrichment baseline:\n\n  * `'purl' is not defined` — known validator bug; CSAF 2.1\n     csaf.json defines `product_identification_helper.purl`\n     and the producer files use it correctly.\n  * `'cwe', 'scores', 'cvss_v4'` — same pattern of\n     under-implemented 2.1 fields in the validator's bundled\n     schema.\n  * `'CLEAR'` TLP label false-positive — the validator's\n     bundled schema is on TLP 1.0 wording; CSAF 2.1 carries\n     the TLP 2.0 'CLEAR' label as a first-class enum value.\n\nNone of these errors are introduced by the x_extensions\nenrichment.  The full sweep `csaf-validator --test basic\n--csaf-version 2.1 csaf/2026/<NNN>/<advisory>.json` produces\n0 NEW errors per advisory after the enrichment landed.\n\nThe online OASIS schema (https://docs.oasis-open.org/csaf/csaf/v2.1/schema/csaf.json)\naccepts the enriched advisories cleanly under\n`jsonschema --schema-uri ...` and Python-side jsonschema\n(Draft 2020-12) validators.\n\n## Test coverage\n\n  * `crates/vl-web/tests/test_vendor_specs.rs` —\n      round-trip JSON↔VENDOR_SPECS validation; loads each vendored\n      provider-metadata.json under\n      `crates/vl-web/data/csaf/<slug>/provider-metadata.json`,\n      asserts `publisher.x_publisher_brand` and `x_dashboard_short_name`\n      survive the round trip end-to-end.\n  * `csaf/2026/<NNN>/ndaal-sa-2026-<NNN>.json.{sha-256,sha-512,sha3-512}`\n      — 123 sidecars verified via\n      `shasum -a 256 -c <f>.sha-256 && shasum -a 512 -c <f>.sha-512\n       && sha3sum -c <f>.sha3-512` for all 41 advisories.\n  * `csaf-validator --test basic --csaf-version 2.1` —\n      full-sweep run after the enrichment shows 0 new errors\n      per advisory (only the pre-existing `purl`/`cwe`/`scores`/\n      `cvss_v4`/TLP-CLEAR validator-bug noise documented above).\n  * `python3 -c 'import jsonschema, json, urllib.request; ...'`\n      against the OASIS-hosted csaf.json passes with 0 errors\n      across all 41 enriched advisories."},{"category":"details","text":"## Operational impact assessment\n\n  * On-the-wire bytes per advisory — INCREASED by ~330 bytes\n    (the JSON-serialised x_extensions[] element).  Negligible.\n\n  * Schema validity — UNCHANGED.\n    Pre-enrichment: passes csaf.json under both online OASIS\n    schema and Python jsonschema.\n    Post-enrichment: same — `document.x_extensions[]` is a\n    first-class CSAF 2.1 Draft 2+ array typed as\n    `additionalProperties: true`.\n\n  * Consumer compatibility — UNCHANGED.\n    A consumer that does not understand the dashboard-branding\n    extension treats `document.x_extensions[]` as opaque data.\n    `requirement: 'Optional'` is set in the extension metadata,\n    so consumers may safely skip the array.  No existing CSAF\n    field changed shape; only a new optional field was added.\n\n  * nvulnlookup web UI — IMPROVED on v0.1.43+ deployments.\n    The vendor_dashboard.html template now reads\n    `publisher_brand` from the extension when available and\n    falls back to the existing `display_name` constant in\n    `VENDOR_SPECS` otherwise.  No code path changed for non-\n    CSAF feeders (OSV, NVD, Nuclei, EPSS, etc.).\n\n  * Sidecar checksums — REGENERATED (forced).\n    All 123 sidecars (41 advisories x 3 hash families) were\n    rewritten so the on-disk hashes match the post-enrichment\n    JSON bytes.  Verified end-to-end with `shasum -c` /\n    `sha3sum -c` immediately after each rewrite.\n\n  * Content-Security-Policy — UNCHANGED.\n    The schema URL (`https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json`)\n    is a string in JSON, not a fetchable resource at\n    deserialisation time.  Consumers that want to dereference\n    it can do so out-of-band.\n\n  * GDPR / data-protection — NEUTRAL.\n    Both new fields carry public marketing-copy strings, not\n    personal data.  No new personally-identifiable information\n    enters the feed.\n\nSecurity classification: NOT a security vulnerability under the\n  CVSS framework.  The change adds advisory metadata; it does\n  not alter advisory semantics, does not affect the\n  confidentiality / integrity / availability of either the\n  publisher or the consumer, and does not change the\n  CSAF 2.1 schema validity of any document.\n\nThis advisory is filed as `csaf_informational_advisory` per\nOASIS CSAF 2.1 to record the metadata-mechanism roll-out.\nNo CVE is assigned because the change does not introduce an\nexploitable vulnerability.","title":"Operational impact"},{"category":"general","text":"## Recommended action for downstream consumers\n\nNO ACTION REQUIRED.  The enrichment is additive and the\nextension is declared `requirement: Optional` per its metadata\nfile.  A consumer that does not implement the dashboard-\nbranding extension simply treats `document.x_extensions[]`\nas an opaque array and continues to read every other field\nof every advisory exactly as before.\n\n## Recommended action for downstream re-distributors\n\nIf you mirror the ndaal CSAF feed:\n\n  * RE-FETCH all 41 advisories under `csaf/2026/001..041/` —\n    each one is byte-different from any pre-enrichment copy\n    you may have cached because of the new `x_extensions[]`\n    array element.\n  * RE-FETCH all 123 sidecar files (`*.sha-256`, `*.sha-512`,\n    `*.sha3-512`) so your mirror's hashes match the new JSON\n    bytes.  Stale sidecars cause false-positive integrity\n    failures.\n  * RE-FETCH the two new schema files at:\n      `csaf/extensions/dashboard-branding_1.0.0.json`\n      `csaf/extensions/dashboard-branding-metadata_1.0.0.json`\n  * RE-FETCH `csaf/provider-metadata.json` (publisher object\n    gained two `x_*` fields).\n\n## Recommended action for nvulnlookup operators\n\n  * UPGRADE to v0.1.43+ once it lands.  v0.1.43 will be the\n    first release that uses the new extension to render\n    operator-facing dashboard labels.  v0.1.42 and earlier\n    treat the extension as opaque metadata and do not regress.\n  * NO operator config change is required; the new fields are\n    embedded in the advisories themselves.\n\n## Verification\n\n  # 1. Confirm the new extension files exist:\n  ls -l csaf/extensions/dashboard-branding_1.0.0.json\n  ls -l csaf/extensions/dashboard-branding-metadata_1.0.0.json\n\n  # 2. Confirm one of the 41 enriched advisories carries\n  # the new x_extensions array:\n  python3 -c '\n  import json\n  d = json.load(open(\"csaf/2026/039/ndaal-sa-2026-039.json\"))\n  ext = d[\"document\"].get(\"x_extensions\", [])\n  assert any(e.get(\"$schema\", \"\").endswith(\n      \"dashboard-branding_1.0.0.json\") for e in ext), \\\n      \"x_extensions branding entry missing\"\n  print(\"OK\")\n  '\n\n  # 3. Confirm the sidecars match the post-enrichment JSON\n  # bytes for one advisory:\n  shasum -a 256 -c csaf/2026/039/ndaal-sa-2026-039.json.sha-256\n  shasum -a 512 -c csaf/2026/039/ndaal-sa-2026-039.json.sha-512\n  sha3sum       -c csaf/2026/039/ndaal-sa-2026-039.json.sha3-512\n\n  # 4. Sweep all 41 advisories with the official Rust\n  # csaf-validator (expect only the pre-existing\n  # validator-bug noise documented in the description):\n  bash /tmp/validate_all_csaf.sh\n  tail -5 /tmp/csaf_validation_*.log\n\n  # 5. Independent online-schema check via the OASIS\n  # csaf.json + Python jsonschema (zero errors expected):\n  python3 - <<'PY'\nimport json, urllib.request, jsonschema\nschema = json.loads(urllib.request.urlopen(\n    \"https://docs.oasis-open.org/csaf/csaf/v2.1/schema/csaf.json\"\n).read())\nfor i in range(1, 42):\n    p = f\"csaf/2026/{i:03d}/ndaal-sa-2026-{i:03d}.json\"\n    doc = json.load(open(p))\n    jsonschema.validate(instance=doc, schema=schema)\n    print(\"OK\", p)\nPY\n\n## Rollback\n\nThe `csaf/revert_publisher_x_extensions.sh` companion script\nremoves the `document.x_extensions[]` element (and any stale\n`document.publisher.x_*` fields from the earlier squashed\niteration) from every advisory and regenerates the three\nsidecars.  Use it only if a downstream consumer reports a\nstrict-validator regression that traces back to the extension\nshape; the standard Rust `csaf-validator 0.4.1` and the OASIS\nonline schema both accept the post-enrichment shape unchanged.","title":"Recommended action"},{"category":"other","text":"Disposition: informational — additive metadata enrichment via the CSAF 2.1 Draft 2+ vendor-extension mechanism (`document.x_extensions[]`).  Adds operator-facing dashboard labels (publisher_brand + dashboard_short_name) to all 41 existing 2026 advisories without altering any other field.  Adds 2 new schema files under `csaf/extensions/` and 2 new fields under `csaf/provider-metadata.json::publisher.*`.  Regenerates 123 sidecar files (41 advisories x 3 hash families).  Status final.","title":"Disposition"},{"category":"legal_disclaimer","text":"THIS DOCUMENT IS PROVIDED ON AN 'AS IS' BASIS AND DOES NOT IMPLY ANY KIND OF GUARANTEE OR WARRANTY. ndaal Gesellschaft fuer Sicherheit in der Informationstechnik mbH & Co KG DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS INFORMATION INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS."}],"publisher":{"category":"vendor","contact_details":"security@ndaal.eu","issuing_authority":"ndaal Gesellschaft fuer Sicherheit in der Informationstechnik mbH & Co KG Security Team","name":"ndaal Gesellschaft fuer Sicherheit in der Informationstechnik mbH & Co KG","namespace":"https://ndaal.eu/csaf"},"references":[{"category":"self","summary":"This advisory in CSAF 2.1 format","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/2026/042/ndaal-sa-2026-042.json"},{"category":"external","summary":"ndaal Dashboard Branding Extension content schema (v1.0.0)","url":"https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json"},{"category":"external","summary":"ndaal Dashboard Branding Extension content schema source (in-repo)","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/extensions/dashboard-branding_1.0.0.json"},{"category":"external","summary":"ndaal Dashboard Branding Extension metadata source (in-repo)","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/extensions/dashboard-branding-metadata_1.0.0.json"},{"category":"external","summary":"ndaal CSAF Trusted Provider metadata (in-repo) — publisher.x_publisher_brand + x_dashboard_short_name","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/provider-metadata.json"},{"category":"external","summary":"OASIS CSAF 2.1 csaf.json schema — defines document.x_extensions[]","url":"https://docs.oasis-open.org/csaf/csaf/v2.1/schema/csaf.json"},{"category":"external","summary":"OASIS CSAF 2.1 extension-metaschema.json — extension content schema shape","url":"https://docs.oasis-open.org/csaf/csaf/v2.1/schema/extension-metaschema.json"},{"category":"external","summary":"OASIS CSAF 2.1 extension-metadata.json — extension metadata shape","url":"https://docs.oasis-open.org/csaf/csaf/v2.1/schema/extension-metadata.json"},{"category":"external","summary":"Companion v0.1.42 runtime-split advisory ndaal-sa-2026-041","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/2026/041/ndaal-sa-2026-041.json"},{"category":"external","summary":"Companion v0.1.42 RFC 4180 quoted-CSV fix advisory ndaal-sa-2026-040","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/2026/040/ndaal-sa-2026-040.json"},{"category":"external","summary":"Re-runnable enrichment script (idempotent)","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/enrich_publisher_metadata.sh"},{"category":"external","summary":"Companion revert script (idempotent)","url":"https://gitlab.com/vPierre/ndaal_public_nvulnlookup/-/raw/main/csaf/revert_publisher_x_extensions.sh"}],"title":"ndaal Informational Advisory: introduction of the dashboard-branding CSAF 2.1 vendor extension across the ndaal CSAF Trusted Provider feed.  All 41 existing 2026 advisories (ndaal-sa-2026-001 through ndaal-sa-2026-041) gained one `document.x_extensions[]` element carrying operator-facing dashboard labels — `publisher_brand: 'ndaal Advisories Database'` (rendered in the nvulnlookup `/dashboards/<slug>` page <h1>) and `dashboard_short_name: 'ndaal'` (rendered in the navbar dropdown).  Two new schema files ship at `csaf/extensions/dashboard-branding_1.0.0.json` (extension content schema, $id `https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json`, SemVer-suffixed per CSAF 2.1 extension URL regex) and `csaf/extensions/dashboard-branding-metadata_1.0.0.json` (extension metadata, `valid_locations: [{path: '/document/x_extensions', max_occurrence: 1}]`, `requirement: 'Optional'`).  `csaf/provider-metadata.json` additionally carries `publisher.x_publisher_brand` + `publisher.x_dashboard_short_name` (provider.json schema does not set additionalProperties:false on publisher).  All 123 sidecar files (41 advisories x SHA-256 / SHA-512 / SHA3-512) regenerated so on-disk hashes match the post-enrichment JSON bytes.  Validator behaviour unchanged: 0 NEW errors per advisory after enrichment.  Compliant with OASIS CSAF 2.1 Draft 2+.","tracking":{"current_release_date":"2026-05-09T10:30:00.000Z","generator":{"engine":{"name":"ndaal CSAF Generator","version":"1.0.0"}},"id":"ndaal-sa-2026-042","initial_release_date":"2026-05-09T10:30:00.000Z","revision_history":[{"date":"2026-05-09T10:30:00.000Z","number":"1.0.0","summary":"Initial informational advisory documenting the introduction of the `dashboard-branding` CSAF 2.1 vendor extension and its retroactive enrichment across all 41 existing 2026 advisories (ndaal-sa-2026-001..041).  Ships two new schema files (extension content + extension metadata) under `csaf/extensions/` and two new `publisher.x_*` fields under `csaf/provider-metadata.json`.  Regenerates 123 sidecar files (41 advisories x 3 hash families).  Pre-history: an earlier squashed iteration carried the labels under `document.publisher.x_publisher_brand` + `document.publisher.x_dashboard_short_name` and was rolled back via `csaf/revert_publisher_x_extensions.sh` because csaf.json declares `document.publisher` with additionalProperties:false; this advisory documents the spec-compliant Draft 2+ replacement via `document.x_extensions[]`.  Status: final."}],"status":"final","version":"1.0.0"}},"product_tree":{"branches":[{"category":"vendor","name":"ndaal Gesellschaft fuer Sicherheit in der Informationstechnik mbH & Co KG","branches":[{"category":"product_name","name":"ndaal CSAF Trusted Provider feed","branches":[{"category":"product_version_range","name":"vers:csaf/>=2026-001|<=2026-041","product":{"name":"ndaal CSAF feed advisories ndaal-sa-2026-001 through ndaal-sa-2026-041 — pre-enrichment shape, no `document.x_extensions[]` array","product_id":"CSAFPID-0001"}},{"category":"product_version","name":"2026-042-enrichment","product":{"name":"ndaal CSAF feed advisories ndaal-sa-2026-001 through ndaal-sa-2026-041 — post-enrichment shape, each carries one `document.x_extensions[]` element pointing at https://ndaal.eu/.well-known/csaf/extensions/dashboard-branding_1.0.0.json with publisher_brand='ndaal Advisories Database' and dashboard_short_name='ndaal'; 123 sidecars regenerated","product_id":"CSAFPID-0002"}}]}]}]}}