Files
git.stella-ops.org/docs/policy/effective-severity.md
StellaOps Bot 9f6e6f7fb3
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
Policy Simulation / policy-simulate (push) Has been cancelled
SDK Publish & Sign / sdk-publish (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
up
2025-11-25 22:09:44 +02:00

57 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Effective Severity Selection
Last updated: 2025-11-25 (Docs Tasks Md.V)
## Goal
Provide a deterministic, explainable way to pick the *effective* severity for a vulnerability or VEX observation when multiple signals exist (CVSS, KEV, exploit intel, VEX status, asset criticality, policy overrides).
## Inputs
- **Base scores**: CVSS v3/v4 (base + temporal) and ecosystem-native severities (npm/yarn, PyPI, Maven). Missing scores are treated as `null`.
- **Exploitability**: KEV flag, EPSS probability, in-the-wild sightings, vendor exploit flags.
- **VEX status**: `not_affected`, `affected`, `fixed`, `under_investigation`, `unknown` (per OpenVEX/CSAF/CycloneDX-VEX).
- **Context signals**: asset criticality, exposure surface (`internet`, `intranet`, `airgap`), runtime enablement flag, workload type.
- **Policy overrides**: tenant/org rules (allow lists, waiver ids, force-upgrade requirements, SLA class).
## Algorithm (deterministic)
1) **Normalize** all scores to a 010 float with 3-decimal rounding; store provenance for each signal.
2) **VEX gate**
- `not_affected` → effective severity `None` (score 0). Short-circuit unless override `force_evaluate=true`.
- `fixed` → keep score but add mitigation note.
3) **Exploit boost**: if `KEV=true` or `EPSS >= 0.7`, set `exploit_boost = +1.0` (cap at 10). Record reason.
4) **Exposure clamp**
- `airgap` → max score 7.0 unless override `allow_airgap_breakglass`.
- `intranet` → no cap; `internet` → no cap.
5) **Criticality weight**: multiply by asset criticality weight (default 1.0; high=1.2, medium=1.0, low=0.8). Clamp 010.
6) **Policy override**: apply explicit tenant rules (force severity, waive to `None`, or constrain max). Overrides always log the applied rule id.
7) **Bucket** into severity bands (stable mapping):
| Score range (inclusive) | Band |
| --- | --- |
| 9.010.0 | Critical |
| 7.08.9 | High |
| 4.06.9 | Medium |
| 0.13.9 | Low |
| 0 | None |
All arithmetic uses `decimal` and rounds only when persisted or returned (3 decimals) to stay replayable.
## Examples
- CVSS 7.5 + KEV + internet + high criticality → base 7.5 → +1.0 exploit → *before clamp* 8.5 → ×1.2 = 10.2 → clamp 10.0 → **Critical**.
- CVSS 5.0, `not_affected` VEX → short-circuit to **None** (score 0) with rationale `vex:not_affected`.
- No CVSS, EPSS 0.2, exposure `airgap` → default score 0, band **None**; remains deterministic.
## Observability
- Emit `stellaops.policy.effective_severity` histogram (010) with tags `tenant`, `source`, `vex_status`, `kev`, `epss_bucket`, `criticality`, `override_id`.
- Log structured event `severity.selected` containing input signals, applied steps, final score/band.
- Traces: span attribute `severity.score` and `severity.band`; link to upstream ingest span (`traceparent` propagated).
## Determinism & Offline posture
- No live network lookups during evaluation; KEV/EPSS/VEX feeds must be preloaded from frozen bundles.
- Sorting of tied severities: break ties by subject id (lexicographic) then source priority (`vex` > `kev` > `cvss` > `ecosystem`).
- All timestamps are UTC ISO-8601; caches keyed by `(tenant, subject, advisory)`.
## Contract for consumers
- API and CLI MUST return both the raw inputs and the chosen band/score so auditors can replay decisions.
- Downstream UIs should surface the rationale chain (steps 26) and any overrides applied.
- Waivers must reference the override id that changed the severity.