Every CVE ships a risk vector. CVE Radar reads it in English, no LLM.
CVE Radar turns the raw NVD feed into a skimmable bulletin: every CVSS vector decoded into one plain-English sentence by a pure function, no language model, so the static build stays reproducible.
Every disclosed vulnerability carries a string that looks like this:
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. It is the CVSS vector, and it is precise:
it tells you exactly how a bug is reached and what it costs you. It is also
unreadable at a glance, which is a problem when the question in your inbox is
"are we affected by this, and how much should I care?" That vector says:
exploitable over the network, no privileges, no user interaction, full loss of
confidentiality, integrity, and availability. In other words, drop everything.
What it is
CVE Radar is a normalization and
presentation layer over the National Vulnerability Database
feed. The NVD is the authoritative public record of software vulnerabilities,
but it is built for machines: deeply nested JSON, four coexisting generations of
CVSS scoring (v2, v3.0, v3.1, v4.0) that use different metric keys in the same
feed, affected-product data buried inside cpe:2.3: match strings, and
descriptions written for scanners rather than for the engineer triaging their
morning. CVE Radar ingests recent CVEs, flattens every one into a single clean
schema, and renders a fast, filterable static bulletin. It is for engineers and
small-team admins who get asked "are we affected?" and have to answer without a
dedicated threat-intel analyst.
The vector, decoded by a pure function
The headline feature is the plain-English sentence, and the interesting design
decision is what generates it: not a language model, a
pure function.
The CVSS specification already defines exactly
what each metric means, so the vector is a total description of the risk shape,
not a summary that needs interpreting. AV:N is network reachability, PR:N is
no privileges required, UI:N is no user interaction, C:H/I:H/A:H is full
impact across the triad. CVE Radar parses those fields and assembles a sentence
from them deterministically. Same vector in, same sentence out, every time.
That choice buys three things at once. The build is reproducible: rerun it and nothing shifts under you. It costs nothing and calls nothing: no API key, no per-request bill, no runtime dependency on a service that might change its mind. And it never hallucinates, because there is no room to: the sentence is a mechanical translation of a formal spec, not a guess. A model would be flashier and, for this job, strictly worse.
Taste in the messy middle
The part a naive "just wrap the API" clone gets wrong is the normalization. When
a record carries multiple CVSS versions, which score do you show? CVE Radar
applies a version precedence and prefers the Primary metric over any Secondary
one, so the number on the card is the one NVD itself would lead with. Affected
software comes from parsing CPE match strings into readable vendor and product
tags. Records with no CVSS data at all degrade gracefully instead of crashing
the batch, which matters because a live feed is messy: normalize.py is fully
covered and fuzzed with Hypothesis, so a
malformed record drops one card rather than the whole build.
The core is Python standard library only, urllib and json, no heavy
dependencies. The frontend is hand-written HTML, CSS, and vanilla JS with
relative asset paths, which is why it hosts under a subpath like
apps.charliekrug.com/cve-radar with no server behind it. Filtering by
severity, vendor, product, and free text all happens client-side over a bounded
snapshot, so it is instant.
The honest limitation is right there in the word "snapshot." The build bakes a point-in-time slice of the NVD into one directory of static files; it is a bulletin, not a live monitor, and the footer says so and links back to the source. There is no alerting, no saved searches, and no EPSS or KEV enrichment yet. A static page that is honest about being point-in-time beats a dynamic one that pretends to be current and quietly goes stale.
Try it
Open CVE Radar, sort by severity, and
read the top card's sentence before you read anything else: you will know in one
line whether it is a remote no-interaction disaster or a local low-severity
nuisance. Filter to a vendor you actually run, then copy the URL, the filtered
view is a shareable deep link. If you would rather read the vector-to-prose logic
than trust it, the code is on GitHub, and
the build emits a clean data.json you can build your own thing on.
This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.
Loading comments…