CSAF/VEX 5.9.2 catalogue and CI validation - #28
Conversation
Commit the CNA records and VEX overlay for the 5.9.2 bullet CVEs, plus publish tooling. CI regenerates CSAF/VEX and runs Secvisogram plus CycloneDX strict checks so an incomplete or non-conformant catalogue cannot merge.
cbe75d8 to
3649396
Compare
MarkAtwood
left a comment
There was a problem hiding this comment.
Approving to merge as the foundation — the architecture is right and the interfaces are stable. The overlay schema is unchanged, and the pin-list format, record layout, and .well-known/csaf tree shape are unaffected by every follow-up below. Generated trees are gitignored, so regenerating after any fix is free. Nothing here publishes, so no bad data escapes by merging.
Two things to settle before this catalogue gets treated as source of truth:
1. CVE-2026-6679 and CVE-2026-6681 look like 5.9.1 fixes, not 5.9.2. Both are pinned in advisories/releases/5.9.2.cves, but every field says 5.9.1: record lessThanOrEqual: 5.9.0 (the other 30 say 5.9.1), overlay fixed_versions: ["5.9.1"] (other 30 say ["5.9.2"]), remediation "Update to wolfSSL 5.9.1 or later", and the detail prose says "fixed in the 5.9.1 release". Both cite PR 10116. They match the signature of the two pre-existing 5.9.1 records (CVE-2026-5501, CVE-2026-5778), which are correctly absent from the pin list. CVE-2026-6679 is High (8.8). Either drop them from the pin list or correct their version metadata — as-is the 5.9.2 advisory claims credit for fixes 5.9.1 shipped.
2. Worth confirming the pin list is complete. _BULLET_CVE_RE (central/advisory-completeness:83-86) captures one id per bullet, so * [High] CVE-A and CVE-B and * [Medium] CVE-A, CVE-B both silently lose the second id — and cves_fixed_in_release only ever adds to found, with the only guard firing when every bullet misses. A partial miss is indistinguishable from a complete release and exits 0. Since 5.9.2.cves was transcribed with this same rule, a loose CVE-[0-9]{4}-[0-9]{4,} count over the real ChangeLog's Vulnerabilities section, diffed against the 32 pinned ids, would settle it. Suggested fix for the tool: compute both the strict and loose sets and fail loudly naming any id the strict rule dropped.
Notable follow-ups, none blocking:
- No CVSS reaches the output. All 34 records are v4.0 only;
gen-advisory:608-610emitsscores[]only for v2/v3 because the CSAF 2.0 schema predates v4, so_best_cvss_csaf20returnsNoneevery time. Consumers get advisories with no severity data, and mandatory tests 6.1.8-6.1.11 are vacuous. The CVSS data itself is the cleanest part of this PR — I recomputed all 34 vectors independently and everybaseScore/baseSeveritymatches — so it's a shame none of it ships. csaf-verify's signature check is circular. It loads the trust anchor from the tree under test (:39) with no fingerprint pin and never readsprovider-metadata.json. Someone with write access to the web root can swap the key, re-sign, regenerate sidecars, and getOKon everything. It also globs only what's on disk and ignoresindex.txt, so deleting a published advisory is invisible — I got1/1 documents verified, exit 0, withindex.txtstill listing two paths.- Neither
csaf-verifynorcsaf-keygenis ever executed — both workflows onlypy_compilethem, which doesn't resolve imports, so the top-levelimport pgpy(undeclared in any manifest) is invisible to CI. Pointed at the default unsigned publish tree,csaf-verifydies with an uncaughtFileNotFoundError. Given that, consider dropping both from this tree until key custody is settled (scoping doc W2) — a verifier that exists, is never run, and doesn't actually verify is worse than none, because the next person will assume it works. Costs nothing to reintroduce. csaf-keygen:49writes the secret key world-readable (0664 under umask 0002) and unencrypted — nochmod, noopener=, so the permissive bits exist before the key bytes land. Fine for a PoC key, must be fixed before real key material.- Validator deps aren't pinned.
.gitignore:25ignorespackage-lock.jsonandadvisory.yml:65usesnpm install --no-save, so 19 packages resolve fresh per run with lifecycle scripts enabled. Andcyclonedx-bom==7.*pins a CLI that's never invoked — the schema comes fromcyclonedx-python-lib, floating>=8.0,<12. Both contradictcsaf_validate.mjs:10. - The validator self-test can't detect losing the mandatory tests. Its fixture already fails strict schema, so the assertion passes either way — stubbing
gateTestsdown to schema-only leaves all four assertions printingok. A schema-valid but mandatory-test-violating fixture would fix it. csaf-publishignoresSOURCE_DATE_EPOCH(:142) thoughgen-advisory:188-194honors it anddocs/PLAN.mdnames it the reproducibility mechanism;provider-metadata.jsonis also never hashed or signed.- Smaller:
--releaseis silently ignored when--cve-listis given (--release 9.9.9against the 5.9.2 list printswolfSSL 9.9.9, 32/32, exit 0, and that label feeds the--jsonconsumer); CVE-2026-6681's CWE-120 name is missing('Classic Buffer Overflow'); tracking ids differing only in case collide after canonicalization and one document is silently dropped;csaf-publish:18says signing is delegated togpgbut_sign()uses pgpy; nopermissions:block on either workflow.
One structural note: the bundle-membership check at advisory.yml:99-119 is near-tautological — pin and the copied records both derive from 5.9.2.cves, so it catches gen-advisory dropping a CVE but never a wrong pin. That's why item 1 above passed green CI.
What holds up well: CI genuinely fails closed (mutating a doc to violate 6.1.1 and 6.1.14/15 each exits 1), no continue-on-error or || true, pull_request rather than pull_request_target. The overlay validates clean against the schema, coverage matches in both directions, canonical_filename isn't path-traversable, and the record data is otherwise solid — 34 distinct titles and descriptions, no placeholders, dates consistent throughout. test_csaf_publish.py is a proper test: it recomputes digests independently rather than round-tripping through the tool.
CVE-2026-6679 and CVE-2026-6681 shipped in 5.9.1. Completeness now fails on ids the strict bullet rule drops, and publish/verify/CI close the rest of the review on #28. Co-authored-by: Cursor <cursoragent@cursor.com>
CVE-2026-6679 and CVE-2026-6681 shipped in 5.9.1. Completeness now fails on ids the strict bullet rule drops, and publish/verify/CI close the rest of the review on #28.
CI loops advisories/releases/<version>/ instead of naming 5.9.2. 5.9.1 is a full pin (ChangeLog bullets plus late disclosures 6679/6681) so a second release proves the same path works for any version.
bbd5fb7 to
09c8c67
Compare
|
Thanks for the review. Both source-of-truth items and the follow-ups are in this branch. Generated trees stay gitignored; still nothing publishes. CVE-2026-6679 and CVE-2026-6681 are out of the 5.9.2 pin and out of the wolfssl-5.9.2 bundle. Records and overlay stay as 5.9.1 (fixed_versions: ["5.9.1"], PR 10116). They live in advisories/releases/5.9.1/ (supplemental — disclosed on the 5.9.2 ChangeLog, shipped in 5.9.1) and in advisories/releases/5.9.2/prior-release.cves. Completeness now requires overlay fixed_versions to contain the release, so this class of pin error fails CI. Completeness computes strict (bullet heads) and loose (every CVE in the Vulnerabilities section). A drop is a hard fail unless it is listed in mentions.cves. 5.9.2 mentions is CVE-2026-5460 (body of 7531). CI reconciles each pin against a frozen ChangeLog in that release directory, not against a copy of the pin. Follow-ups: CSAF 2.0 still cannot put v4 in scores[]. CycloneDX 1.6 carries the v4 rating; CI fails if any pinned vuln lacks one. CSAF keeps the CVSS v4 note. |
CVE-2026-6679 and CVE-2026-6681 shipped in 5.9.1. Completeness now fails on ids the strict bullet rule drops, and publish/verify/CI close the rest of the review on #28.
Summary
csaf-publish/csaf-verify).advisories/releases/5.9.2.cves. Completeness counts only* [High] CVE-…bullets, so predecessor ids named in a paragraph are not members.selfURL publish checks. Generated trees are gitignored.Test plan
python3 -m unittest central/test_advisory_completeness.py central/test_csaf_publish.py central/test_gen_advisory.pypython3 central/advisory-completeness --cve-list advisories/releases/5.9.2.cvesAdvisory catalogueworkflow is green (generate 5.9.2, Secvisogram, CycloneDX, unsigned publish)advisories/out/andadvisories/publish/are not in the PR