Version Notes
Per-version quirks and spec compliance notes
Vector-string prefixes
The CVSS:x.y/ prefix is mandatory from CVSS v3.0 onward. v1.0 and v2.0 predate it, so their vectors are normally written bare — CVSS.parse accepts them with or without the parentheses NVD renders them in, and tolerates a CVSS:1.0/ or CVSS:2.0/ prefix that some tools add for symmetry with v3+.
The prefix literal is matched case-insensitively (cvss:3.1/… parses like CVSS:3.1/…), because lower- and mixed-case spellings turn up in real feeds. Metric keys and values stay case-sensitive, as the specs require.
A prefix-less string carrying v3.x or v4.0 metrics is reported as an error rather than guessed at — for v3.x the prefix is the only thing that separates v3.0 from v3.1, and the two use different RoundUp and modified-impact formulas:
CVSS.parse("AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
# CVSS::ParseError: vector carries CVSS v3.x metrics but no 'CVSS:3.0/' or 'CVSS:3.1/' prefix; ...
CVSS v1.0
- No standardised vector string. The FIRST v1.0 guide defines metrics and formulas but never a vector notation. This library uses NVD's — parentheses around the metric list, e.g.
(AV:R/AC:L/Au:NR/C:C/I:C/A:C/B:N)— which is what every v1-era publisher emitted and what NVD documented atnvd.nist.gov/cvss.cfm?vectorinfo.parsealso accepts the list without parentheses and with aCVSS:1.0/prefix;to_salways emits the canonical parenthesised form. - Impact Bias (
B) is v1-only. It re-weights the three impact sub-scores against one another (Normalsplits them 0.333/0.333/0.333; a biased value gives the favoured impact 0.5 and the other two 0.25 each). v2.0 dropped the metric and reintroduced the idea as the environmentalCR/IR/ARrequirements.Bis a required base metric —parserejects a vector without it, and it is also whatCVSS.parsekeys version detection off: NVD renders v2.0 vectors parenthesised too, so parentheses alone cannot mean v1.0. - Binary base metrics.
AVis Remote/Local (no Adjacent Network), andAuis Required/Not-Required (no Single/Multiple split).AV:R,Au:NR,RL:O/RL:T, andE:Pare all v1 spellings that mean something different — or nothing — in v2.0. RC:Uc(Uncorroborated) is written mixed-case in NVD's legend. Upper-caseRC:UC— the code v2.0 later assigned to Unconfirmed — appears in the wild too, so both are accepted on input;to_snormalises toUc.- No "Not Defined" values. Unset temporal metrics score as the neutral 1.0, so
temporal_scorecollapses tobase_score; unset environmental metrics leaveenvironmental_scoreequal totemporal_score.TD:Nstill legitimately zeroes the environmental score. - Official-Fix weighs 0.87. The worked examples in the guide label it "(0.90)" in their summary tables, but only 0.87 — the value in the normative formula section — reproduces the 7.0 / 8.3 / 4.4 results printed beside them.
- Severity bands are NVD's Low/Medium/High; the v1.0 spec defines no qualitative ratings at all.
Severity::Noneis returned for0.0, andCriticalnever appears. - Environmental vector notation is an extension. NVD only ever published base and temporal vectors, so
CDPandTDreuse the short codes v2.0 gave them. Vectors that omit them round-trip byte-for-byte either way.
CVSS v2.0
- No prefix in vector strings.
CVSS.parserecognises both prefix-less input and an explicitCVSS:2.0/prefix (some downstream tools emit the latter for symmetry with v3+). - Parentheses are tolerated. NVD's v2 calculator links vectors as
?vector=(AV:N/AC:L/Au:N/C:P/I:P/A:P), and that rendering is common in v2-era data, soparseaccepts it;to_salways emits the bare notation the v2 guide uses. - Severity bands map at most to
High— there is no Critical band.Severity::Noneis returned for0.0, which is a small convenience extension over the strict spec (which only defines Low/Medium/High). - Multi-character codes:
Au(lowercaseu),CDP:LM/CDP:MH,RL:OF/RL:TF,RC:UC/RC:UR,E:POCare all parsed and emitted exactly as written. - Temporal and Environmental metrics are supported.
environmental_scorereduces to0.0whenTD:N.
CVSS v3.0 vs v3.1
Both versions are handled by the same CVSS::V3::Vector class. They share metric definitions and the base scoring formula. They differ in two places:
-
RoundUp algorithm
- v3.0:
ceiling(input × 10) / 10 - v3.1: integer-space spec algorithm that avoids floating-point edge cases on values like
4.65.
- v3.0:
-
Modified Impact polynomial (Environmental score, Scope:Changed)
- v3.0:
7.52 × (ISS - 0.029) - 3.25 × (ISS - 0.02)^15 - v3.1:
7.52 × (ISS - 0.029) - 3.25 × (ISS × 0.9731 - 0.02)^13
- v3.0:
vec.version always returns the parsed version string ("3.0" or "3.1"); round-trips via to_s preserve it.
CVSS v4.0
- Single combined score. Threat (E) and Environmental metrics are folded into a 6-character macro vector that drives a 270-entry lookup table; there are no separate temporal or environmental scores.
vec.environmental_scoreandvec.threat_scoreare aliased tobase_scorefor API symmetry. - Macro vector is exposed via
vec.macro_vectorfor tooling. Format:EQ1 EQ2 EQ3 EQ4 EQ5 EQ6, e.g."000200". - Subsequent System impacts:
SC,SI,SA. Modified counterparts (MSI,MSA) additionally acceptS(Safety), which forcesEQ4 = 0. - Provider Urgency (
U) uses full-word values (Clear,Green,Amber,Red). - Nomenclature (spec §6):
vec.nomenclaturereturns one ofBase(CVSS-B),BaseThreat(CVSS-BT),BaseEnvironmental(CVSS-BE),BaseThreatEnvironmental(CVSS-BTE) based on which optional metric groups carry meaningful (non-X) values. Supplemental metrics never affect the classification. - Implementation source. The lookup tables (
cvssLookup,maxComposed,maxSeverity) and the depth-distance correction are ported verbatim from FIRSTdotorg/cvss-v4-calculator (BSD-2-Clause). Attribution is preserved insrc/cvss/v4/macro_vector.cr.
Cross-version comparisons
Vector includes Comparable(Vector) and orders by base_score, so <, >, and sort all work across versions. Equality, however, is structural — a v3 vector and a v4 vector are never == even when their scores are identical.