product advisories update
This commit is contained in:
@@ -0,0 +1,160 @@
|
||||
## Product Advisory: Deterministic VEX-first vulnerability verdicts with CycloneDX 1.7
|
||||
|
||||
### 1) The problem you are solving
|
||||
|
||||
Modern scanners produce a long list of “components with known CVEs,” but that list is routinely misleading because it ignores *context*: whether the vulnerable code is shipped, configured, reachable, mitigated, or already fixed via backport. Teams then waste time on false positives, duplicate findings, and non-actionable noise.
|
||||
|
||||
A **VEX-first** approach solves this by attaching *exploitability/impact assertions* to SBOM components. In CycloneDX, this is expressed via the **Vulnerability / Analysis** model (often used as VEX), which can declare that a component is **not affected**, **under investigation/in triage**, **exploitable/affected**, or **resolved/fixed**, along with rationale/justification and other details. CycloneDX explicitly frames this as “vulnerability exploitability” context, including a `state` and a `justification` for why a vulnerability is (or isn’t) a practical risk. ([cyclonedx.org][1])
|
||||
|
||||
The core product challenge is therefore:
|
||||
|
||||
* You will ingest **multiple statements** (vendors, distros, internal security, runtime evidence) that may **conflict**.
|
||||
* Those statements may be **conditional** (only affected on certain OS, feature flags, build options).
|
||||
* You must produce a **single stable, explainable verdict** per (product, vuln), and do so **deterministically** so audits and diffs are reproducible.
|
||||
|
||||
---
|
||||
|
||||
### 2) Product intent and outcomes
|
||||
|
||||
**Primary outcome:** Reduce noise while increasing trust: every suppression or escalation is backed by evidence and explainable logic.
|
||||
|
||||
**What “good” looks like:**
|
||||
|
||||
* Fewer alerts, but higher signal.
|
||||
* Each vuln has a clear **final verdict** plus **reason chain** (“why this was marked not_affected/fixed/affected”).
|
||||
* Deterministic replay: the same inputs produce the same outputs.
|
||||
|
||||
---
|
||||
|
||||
### 3) Recommended data contract (CycloneDX 1.7 aligned)
|
||||
|
||||
Use CycloneDX 1.7 as the canonical interchange for impact/exploitability assertions:
|
||||
|
||||
* **SBOM**: components + dependencies (CycloneDX and/or SPDX)
|
||||
* **Vulnerability entries** with **analysis** fields:
|
||||
|
||||
* `analysis.state` (status in context) and `analysis.justification` (why), as described in CycloneDX’s exploitability use case. ([cyclonedx.org][1])
|
||||
* Optional ingress from **OpenVEX** or CSAF; normalize into CycloneDX analysis semantics (OpenVEX defines the commonly used status set `not_affected / affected / fixed / under_investigation`, and requires justification in `not_affected` cases). ([GitHub][2])
|
||||
|
||||
Graph relationships (if you use SPDX 3.0.1 as your internal graph layer):
|
||||
|
||||
* Model dependencies and containment via SPDX `Relationship` and `RelationshipType`, which formalize “Element A RELATIONSHIP Element B” semantics used to compute transitive impact. ([SPDX][3])
|
||||
|
||||
---
|
||||
|
||||
### 4) Product behavior guidelines
|
||||
|
||||
#### A. Single “Risk Verdict” per vuln, backed by evidence
|
||||
|
||||
Expose one final verdict per vulnerability at the product level, with an expandable “proof” pane:
|
||||
|
||||
* Inputs considered (SBOM nodes, relationship paths, VEX statements, conditions).
|
||||
* Merge logic explanation (how conflicts were resolved).
|
||||
* Timestamped lineage: which feed/source asserted what.
|
||||
|
||||
#### B. Quiet-by-design UX
|
||||
|
||||
* Default views show only items needing action: **Affected/Exploitable**, and **Under Investigation** with age/timeouts.
|
||||
* “Not affected” and “Fixed/Resolved” are accessible but not front-and-center; they primarily serve audit and trust.
|
||||
|
||||
#### C. Diff-aware notifications
|
||||
|
||||
Notify only on **meaningful transitions** (e.g., Unknown→Affected, Affected→Fixed), not on every feed refresh.
|
||||
|
||||
---
|
||||
|
||||
### 5) Development guidelines (deterministic resolver)
|
||||
|
||||
#### A. Normalize identifiers first
|
||||
|
||||
Create a strict canonical key for matching “the same component” across SBOMs and VEX:
|
||||
|
||||
1. prefer **purl**, then **CPE**, then (name, version, supplier).
|
||||
2. persist alias mappings (vendor naming variance is normal).
|
||||
|
||||
#### B. Represent the world as two layers
|
||||
|
||||
1. **Graph layer** (what is shipped/depends-on/contains what)
|
||||
2. **Assertion layer** (CycloneDX 1.7 vulnerability analysis statements, plus optional runtime/reachability evidence)
|
||||
|
||||
Do not mix them—keep assertions as immutable facts that the resolver evaluates.
|
||||
|
||||
#### C. Condition evaluation must be total and deterministic
|
||||
|
||||
For each assertion, evaluate conditions against a frozen `Context`:
|
||||
|
||||
* platform (OS/distro/arch), build flags, enabled features, packaging mode
|
||||
* runtime signals (if used) must be versioned and hashed like any other input
|
||||
|
||||
If a condition cannot be evaluated, treat it explicitly as **Unknown**, not false.
|
||||
|
||||
#### D. Merge conflicts via a documented lattice
|
||||
|
||||
Define a monotonic merge function that is:
|
||||
|
||||
* **commutative** (order independent),
|
||||
* **idempotent** (reapplying doesn’t change),
|
||||
* **associative** (supports streaming/parallel merges).
|
||||
|
||||
A pragmatic priority (adjust to your policy):
|
||||
|
||||
1. **Fixed/Resolved** (with evidence of fix scope)
|
||||
2. **Not affected** (with valid justification and conditions satisfied)
|
||||
3. **Affected/Exploitable**
|
||||
4. **Under investigation / In triage**
|
||||
5. **Unknown**
|
||||
|
||||
CycloneDX’s exploitability model explicitly supports “state + justification” to make “not affected” meaningful, not a hand-wave. ([cyclonedx.org][1])
|
||||
|
||||
#### E. Propagation rules must be explicit
|
||||
|
||||
Decide and document how assertions propagate across the dependency graph:
|
||||
|
||||
* When a dependency is **Affected**, does the product become Affected automatically? (Typically yes if the dependency is shipped and used, unless a product-level assertion says otherwise.)
|
||||
* When a dependency is **Not affected** due to “code removed before shipping,” does the product inherit Not affected? (Often yes, but only if you can prove the affected code path is absent for the shipped artifact.)
|
||||
* Keep propagation rules versioned to avoid “policy drift” breaking deterministic replay.
|
||||
|
||||
#### F. Always emit a proof object
|
||||
|
||||
For every final verdict emit:
|
||||
|
||||
* contributing assertions (source IDs), condition evaluations, merge steps
|
||||
* the graph path(s) that made it relevant (SPDX Relationship chain or CycloneDX dependency references)
|
||||
This proof is what lets you be quiet-by-design without losing auditability.
|
||||
|
||||
---
|
||||
|
||||
### 6) Interop guidance (OpenVEX / CSAF → CycloneDX 1.7)
|
||||
|
||||
If you ingest OpenVEX:
|
||||
|
||||
* Map OpenVEX status to CycloneDX analysis state (policy-defined mapping).
|
||||
* Enforce OpenVEX minimums: `not_affected` should have a justification/impact statement. ([GitHub][2])
|
||||
|
||||
If you ingest CSAF advisories:
|
||||
|
||||
* Treat them as another assertion source; do not let them overwrite higher-confidence internal evidence without explicit precedence rules.
|
||||
|
||||
---
|
||||
|
||||
### 7) Testing and rollout checklist
|
||||
|
||||
* **Golden test vectors**: fixed input bundles (SBOM + assertions + context) with expected verdicts.
|
||||
* **Determinism tests**: shuffle assertion ordering; results must be identical.
|
||||
* **Regression diffs**: store prior proofs; verify only intended transitions occur after feed updates.
|
||||
* **Adversarial cases**: conflicting assertions, partial conditions, alias mismatches, missing dependency edges.
|
||||
|
||||
---
|
||||
|
||||
### 8) Common failure modes to avoid
|
||||
|
||||
* Treating “not affected” as a suppression without requiring justification.
|
||||
* Allowing “latest feed wins” behavior (non-deterministic and unauditable).
|
||||
* Mixing runtime telemetry directly into SBOM identity (breaks replay).
|
||||
* Implicit propagation rules (different engineers will interpret differently; results drift).
|
||||
|
||||
If you want, I can also provide a short, implementation-ready “resolver contract” (types, verdict lattice, proof schema) that is CycloneDX 1.7-centric while remaining neutral to whether you store the graph as CycloneDX dependencies or SPDX 3.0.1 relationships.
|
||||
|
||||
[1]: https://cyclonedx.org/use-cases/vulnerability-exploitability/?utm_source=chatgpt.com "Security Use Case: Vulnerability Exploitability"
|
||||
[2]: https://github.com/openvex/spec/blob/main/OPENVEX-SPEC.md?utm_source=chatgpt.com "spec/OPENVEX-SPEC.md at main"
|
||||
[3]: https://spdx.github.io/spdx-spec/v3.0.1/model/Core/Classes/Relationship/?utm_source=chatgpt.com "Relationship - SPDX Specification 3.0.1"
|
||||
Reference in New Issue
Block a user