Vulnerability
KEV::Vulnerability
A single entry from the CISA KEV catalog. Mirrors the official KEV JSON schema.
Includes Comparable(Vulnerability). Equality is structural over every field — see Equality and ordering below.
Fields
| Getter | Type | Required by schema | Description |
|---|---|---|---|
cve_id |
String |
✓ | The CVE ID (e.g. "CVE-2024-1234"). |
vendor_project |
String |
✓ | Vendor / upstream project. |
product |
String |
✓ | Affected product. |
vulnerability_name |
String |
✓ | CISA-set name. |
date_added |
Time |
✓ | UTC midnight; source is YYYY-MM-DD. |
short_description |
String |
✓ | One-paragraph description. |
required_action |
String |
✓ | Remediation guidance. |
due_date |
Time |
✓ | Federal-agency deadline; UTC midnight. |
known_ransomware_campaign_use |
RansomwareUse? |
optional | Known or Unknown, or nil when absent. |
notes |
String? |
optional | Free-form notes (often reference URLs separated by ;). |
cwes |
Array(String) |
optional | Associated CWE codes; always emitted on serialisation (as [] when empty) to match the live feed. |
Construction
KEV::Vulnerability.new(
cve_id: "CVE-2024-1234",
vendor_project: "ACME",
product: "Widget",
vulnerability_name: "ACME Widget RCE",
date_added: Time.utc(2024, 1, 1),
short_description: "...",
required_action: "Apply updates.",
due_date: Time.utc(2024, 1, 22),
known_ransomware_campaign_use: KEV::RansomwareUse::Unknown,
notes: nil,
cwes: ["CWE-79"],
)
The cwes array is dup'd on construction — external mutation of the source array won't bleed into the Vulnerability's state.
| Method | Description |
|---|---|
Vulnerability.from_json(input : String | IO) : Vulnerability |
Parse a single entry from a JSON object. |
Vulnerability.from_json_any(any : JSON::Any) : Vulnerability |
Build from an already-parsed JSON::Any. |
Predicates
| Method | Description |
|---|---|
known_ransomware? : Bool |
true only when CISA confirmed ransomware use (Known). |
overdue?(now : Time = Time.utc) : Bool |
due_date < now. |
days_until_due(now : Time = Time.utc) : Int32 |
Negative once overdue. |
remediation_window_days : Int32 |
dueDate - dateAdded, rounded to whole days. |
has_cwe?(code : String) : Bool |
Numeric-width-normalised CWE check. |
cve_year : Int32 |
The 4-digit year segment of the CVE id. Raises KEV::ParseError if unparseable. |
same_cve?(other : Vulnerability) : Bool |
Same CVE id, regardless of other field differences. |
Equality and ordering
== is structural: every field must match. This keeps the Comparable contract intact (a == b ⟺ (a <=> b) == 0).
For dedup across feed snapshots — where CISA may have edited descriptions or notes — use #same_cve?(other) instead of ==.
<=> orders by date_added (chronological), with cve_id as a stable tiebreak.
catalog.sort.first # oldest entry
catalog.to_a.sort_by(&.due_date) # by deadline
JSON
| Method | Description |
|---|---|
to_json(json : JSON::Builder) : Nil |
Canonical CISA-shaped serialisation. |
to_json : String |
Convenience wrapper. |
to_h : Hash(String, String | Array(String)) |
Plain Hash keyed by canonical field names. |
to_json and to_h always emit cwes (as [] when empty) to match the live feed's behaviour. notes and knownRansomwareCampaignUse are omitted when nil.
See also
- Basic Usage — predicates and equality in context.
- RansomwareUse — the enum used for the ransomware flag.
- Errors — what raises during parsing.