GitHub
ESC

Basic Usage

Parsing & version dispatch

CVSS.parse("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")     # → V3::Vector
CVSS.parse("CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N")  # → V4::Vector
CVSS.parse("CVSS:2.0/AV:N/AC:L/Au:N/C:P/I:P/A:P")              # → V2::Vector
CVSS.parse("AV:N/AC:L/Au:N/C:P/I:P/A:P")                       # → V2::Vector (no prefix)

Typed metric access

Use the version-specific class to read individual metrics with strong typing:

v = CVSS::V3::Vector.parse("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
v.av    # => CVSS::V3::AttackVector::Network
v.s     # => CVSS::V3::Scope::Unchanged
v.c     # => CVSS::V3::Impact::High

Building a vector programmatically

v = CVSS::V3::Vector.new(
  av: CVSS::V3::AttackVector::Network,
  ac: CVSS::V3::AttackComplexity::Low,
  pr: CVSS::V3::PrivilegesRequired::None,
  ui: CVSS::V3::UserInteraction::None,
  s:  CVSS::V3::Scope::Unchanged,
  c:  CVSS::V3::Impact::High,
  i:  CVSS::V3::Impact::High,
  a:  CVSS::V3::Impact::High,
)
v.to_s  # => "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"

Round-tripping

to_s always produces the canonical FIRST ordering:

input  = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F/RL:O/RC:C"
parsed = CVSS.parse(input)
parsed.to_s == input  # => true

Equality and hashing

Vectors are value types — == is structural (same concrete class + same metrics) and they hash consistently:

a = CVSS.parse("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
b = CVSS.parse("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
a == b              # => true
a.hash == b.hash    # => true

set = Set(CVSS::Vector).new
set << a
set << b
set.size            # => 1

Two vectors of different versions are never ==, even when their scores happen to match.

Ordering with Comparable

Vectors include Comparable(Vector) and compare by base_score, so sorting and < / > work — even across versions:

vulns = inputs.map { |s| CVSS.parse(s) }
vulns.sort.last     # most severe vulnerability
vulns.min.base_score

Hash export

to_h returns a Hash(String, String) of metric short-codes in canonical order:

CVSS.parse("CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:F").to_h
# => {"AV" => "N", "AC" => "L", "PR" => "N", "UI" => "N",
#     "S" => "U", "C" => "H", "I" => "H", "A" => "H", "E" => "F"}

Optional metrics that are not set are omitted.