KEV::Vulnerability
Inherits Comparable < Reference < Object
A single entry from the CISA Known Exploited Vulnerabilities catalog.
Mirrors the official JSON schema published at https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities_schema.json
vuln = KEV::Vulnerability.from_json(payload)
vuln.cve_id # => "CVE-2024-1234"
vuln.vendor_project # => "Microsoft"
vuln.known_ransomware? # => true
vuln.overdue? # => false
Equality is structural: two vulnerabilities are == only when every
field matches, so re-parsed snapshots compare equal exactly when their
content is identical.
For the common dedup case ("is this the same CVE, possibly from a
different snapshot?") use Vulnerability#same_cve?(other) instead.
Ordering is by date_added (chronological), with cve_id as a tiebreak
so the sort is stable across entries added on the same day. Entries that
tie on both keep comparing through the remaining fields, so the
Comparable contract holds: a == b ⟺ (a <=> b) == 0.
Constants
Schema-enforced CVE id shape: CVE-YYYY-N{4,}.
Matches the official CISA KEV JSON schema pattern
^CVE-[0-9]{4}-[0-9]{4,}$ — a 4-digit year and a serial of at least
four digits with no upper bound.
See https://cve.mitre.org/cve/identifiers/syntaxchange.html for the
2014 widening from a fixed 4-digit serial.
Schema-enforced CWE shape for entries inside the cwes array.
Constructors
Parses a single Vulnerability from a raw JSON string. Useful in tests and when ingesting per-CVE payloads from upstream stores.
Builds a Vulnerability from a parsed JSON::Any object (a single
element of the catalog's vulnerabilities array).
Raises MissingFieldError when a schema-required field is absent or
ParseError when a date string is malformed.
Class methods
The numeric part of a CWE reference, or nil when code is not one.
Accepts every spelling #has_cwe? does.
Instance methods
Sort by date_added, then cve_id for stability.
(date_added, cve_id) is not unique across snapshots — CISA edits
descriptions, notes, and CWEs in place — so a pair that ties on both
falls through to the remaining fields in a fixed order. That keeps
the Comparable contract this class documents: (a <=> b) == 0
exactly when a == b.
Structural equality — every field must match. See the class doc for the rationale (Comparable contract preservation).
The 4-digit (or longer) year of the CVE assignment. Raises
KEV::ParseError if the CVE id does not have a parseable year
component (cannot happen for schema-validated input, but defensive
against programmatically-constructed Vulnerabilities).
Associated Common Weakness Enumeration codes (e.g. ["CWE-79"]).
Always an array — empty when the field is omitted in the source feed.
Returns a copy: initialize defensively copies the array it is
handed, and this accessor completes the seal at the read end, so a
Vulnerability can never be mutated through the array it hands out.
For read-only traversal prefer #each_cwe, which does not allocate;
for membership tests prefer #has_cwe?.
Date the vulnerability was added to the KEV catalog. CISA publishes
this as YYYY-MM-DD (no time component); represented here as a UTC
midnight Time.
Whole calendar days from now to due_date, in UTC. 0 on the due
date itself (still on time — see #overdue?), positive while the
deadline is ahead, negative once it has passed.
Federal-agency remediation deadline. Same YYYY-MM-DD UTC-midnight
representation as date_added.
Yield each CWE code without copying the backing array. Use this on
hot paths (grouping, counting) where #cwes would allocate a copy
per entry.
Case-insensitive CWE lookup. Accepts "CWE-79", "cwe-79",
"Cwe-79", a bare "79", or zero-padded forms like "CWE-079" —
the numeric portion is compared as an integer, so prefix casing,
surrounding whitespace, widths, and leading zeros don't matter.
Appends a String representation of this object which includes its class name, its object address and the values of all instance variables.
class Person
def initialize(@name : String, @age : Int32)
end
end
Person.new("John", 32).inspect # => #<Person:0x10fd31f20 @name="John", @age=32>
true when CISA has confirmed ransomware-campaign exploitation. Maps
nil and Unknown both to false — the predicate name asks about
confirmed use, and only Known answers yes.
Whether CISA has confirmed ransomware-campaign use. nil only for
legacy entries that predate the field — current feed entries always
populate it. Unknown / future strings (the schema declares this as a
bare type: string, with no enum constraint) parse as nil here and
are preserved verbatim in known_ransomware_campaign_use_raw.
The raw string as it appeared in the feed. Populated for every entry
whose source JSON contained knownRansomwareCampaignUse, including
values that do not match the typed enum (Known / Unknown). Round-trip
JSON serialization prefers this over known_ransomware_campaign_use
so future CISA additions do not silently lose data.
Free-form notes, often reference URLs separated by ;. nil when
absent from the feed entry.
true when the remediation deadline has passed (relative to now,
default Time.utc).
CISA's dueDate names the last day on which remediation is still
on time, and is carried here as UTC midnight opening that day. An
entry is therefore overdue only once the whole due day has elapsed —
i.e. from due_date + 1 day onward. Comparing due_date < now
directly would flag every entry as overdue from one second past
midnight on the day it is actually still due.
Days between date_added and due_date. Useful for spotting unusual
remediation windows (CISA usually sets ~21 days, but some entries get
tighter or much wider deadlines).
True when both records describe the same CVE, regardless of any
other field differences. Use this (not ==) to dedup across feed
snapshots where CISA may have edited descriptions, notes, or CWEs.
One-line, terminal-friendly summary. Useful for logging or
rendering a quick kev | grep pipeline.
Emit this entry as a single CSV row in the canonical CISA column
order (see Catalog::CSV_HEADERS). Multiple CWEs are joined with
", " to match how CISA serializes them.
Returns a Hash(String, String | Array(String)) keyed by the
canonical KEV feed field names. Dates are serialised as
YYYY-MM-DD strings. Optional fields are omitted when not present.
JSON serialization. Field order and naming match the canonical KEV
feed, so to_json output is interchangeable with rows in
vulnerabilities from the official catalog.
Re-run the schema-level shape checks against this record. Useful
after programmatic construction or in-place mutation, when fields
may have skipped the parser path that normally validates them.
Raises KEV::InvalidValueError on the first violation.