Turns a terse CVE record into a plain-language explanation, grounded in NVD's own published data. No LLM in the loop — every line traces back to a specific field NVD returned.
$ python3 -m cve_explain explain CVE-2025-55182
# CVE-2025-55182
> ⚠ Actively exploited in the wild (CISA Known Exploited Vulnerabilities catalog)
In short: CVE-2025-55182 is a critical-severity vulnerability. It's classified
as CWE-502. Affects: react-server-dom-webpack (19.0.0, 19.1.0 through
19.1.1, 19.2.0); react-server-dom-turbopack (...); react-server-dom-parcel (...).
It is also listed in CISA's Known Exploited Vulnerabilities catalog...
## Severity — CVSS 3.1: 10.0 (CRITICAL)
`CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H`
- Attack vector: Can be attacked over the network — no physical or local access needed.
- Privileges required: The attacker needs no account or privileges on the target at all.
- ...
## What kind of bug this is
- CWE-502: Insecure Deserialization — the application reconstructs objects
from untrusted input without proper checks, which can be abused to run
arbitrary code or corrupt program state.
A raw CVSS vector (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) and a CWE number
tell an expert everything and most people nothing. This tool bridges that
gap using only structured NVD fields — the CWE ID, the CVSS metric
letters, the affected version list, the CISA KEV flag — run through two
small hand-written lookup tables (cvss.py, cwe_glossary.py). If NVD
hasn't published a field, the output says so instead of guessing.
pip install -r requirements.txtOptional: set NVD_API_KEY to raise NVD's rate limit from 5 to 50
requests/30s. Request one here.
python3 -m cve_explain explain CVE-2025-55182 # fetch, explain, archive
python3 -m cve_explain explain CVE-2025-55182 # second run: served from archive, no re-fetch
python3 -m cve_explain explain CVE-2025-55182 --force
python3 -m cve_explain explain CVE-2025-55182 --json # structured output for scripting/piping
python3 -m cve_explain list # everything explained so farEach explain writes <CVE-ID>.md and <CVE-ID>.json under
explanations/. Keep running it against new CVE IDs — by hand, from a
feed, from cron, whatever fits your workflow — and that directory
becomes a self-hosted, plain-language CVE archive you can commit to your
own repo.
Optional: set GITHUB_TOKEN to raise the GHSA/patch-diff lookup's rate
limit from 60 to 5000 requests/hour.
| Source | What it gives you | When it's missing |
|---|---|---|
| NVD | description, CWE, CVSS, affected versions, references, CISA KEV flag | Required — lookup fails without it |
| EPSS (FIRST.org) | data-driven probability of real-world exploitation in the next 30 days | Very recently published CVEs aren't scored yet — section omitted |
| GHSA | the actual fix commit, when the advisory links one, with real file-level diff stats | Most CVEs don't have a resolvable commit link — section omitted |
CVSS tells you how bad it is if exploited. EPSS tells you how likely it is to actually get exploited. The two often disagree, and reading only one of them is a common way to mis-prioritize.
python3 -m cve_explain explain CVE-2025-55182 --verify-git
python3 -m cve_explain explain CVE-2025-55182 --verify-git --clone-cache ~/.cache/cve-explain-clonesNVD's own "affected versions" field is a hand-maintained claim, and this
tool has already found it unreliable in a real case (Log4Shell, below).
--verify-git cross-checks it a different way: when the CVE has a
resolvable GitHub fix commit, it clones that repo and asks
Augur's provenance module to find,
from the real commit history itself, when the vulnerable pattern was
actually introduced — not "the last commit that touched the line"
(classic SZZ's well-known weak point) — and which tagged releases
genuinely contain it.
This is deliberately narrow and opt-in:
- It only recognizes one bug shape so far (a fixed-size
memcpyfrom a taintedchar*parameter via one hop of pointer arithmetic). - It clones a real repository, so it's off by default — not something
every
explaincall should silently pay for. - Most CVEs won't match; the report says so plainly ("Not applicable to this CVE: ...") instead of forcing an answer.
When it does match, you get a second, independently-computed opinion on the version range sitting right next to NVD's — worth a look, not a verdict to trust blindly over the other.
-
~30 curated CWE entries. Anything not in
CWE_GLOSSARY(cwe_glossary.py) links to the MITRE definition instead of a guess. Extend the dict as you hit gaps. -
CVSS v3.0/3.1 only. v2 and v4 scores print with their raw vector string and no sentence breakdown — v4 uses a different metric set and isn't handled yet.
-
NVD's
affectedfield is sometimes messy, and this tool works around specific cases it's actually hit, not a hypothetical list:- Pre-2015 CVEs often carry a literal
vendor: "n/a", product: "n/a"placeholder instead of omitting the field — dropped rather than printed as "Affects: n/a (n/a and later)". CVE-2021-44228(Log4Shell) has a non-semver version boundary (lessThan: "log4j-core*") plus a list of version-by-version exceptions — degrades to "2.0-beta9 and later, see description" instead of a fabricated precise range.- The same reference URL sometimes appears twice under different NVD source IDs — deduped.
All three were caught by running the tool against real CVEs, not invented as edge cases; see METHODOLOGY.md.
- Pre-2015 CVEs often carry a literal
-
Explains, doesn't assess exploitability or generate PoCs. Out of scope by design.
-
No model in the loop, so no hallucination risk to guard against. Every sentence maps to a specific field from NVD, EPSS, or a real fetched commit diff. There's nothing here that's free-generated text, so there's nothing that needs a RAG pipeline or fact-checking step to keep honest.
This is a read tool, not an analysis engine. It doesn't scan your codebase for the vulnerability, doesn't reverse-engineer binaries, and doesn't replace a proper vulnerability database like cve-search if what you need is bulk local querying across thousands of CVEs, or a threat-intel platform if what you need is "is this being used in a live campaign against my industry right now." What it does is turn one specific CVE ID into a complete, accurate, single-page answer in a few seconds, pulling three separate free public sources that most people don't think to cross-reference by hand every time.