Where does a CVE actually live, who owns the fix, and is the public PoC real?
A scanner tells you a CVE is "present". It does not tell you that the OS patch you just shipped leaves a second copy of the library bundled inside your runtime, which team owns each copy, or whether the GitHub "exploit" everyone is forwarding does what its README claims.
cve-parser answers those questions from free public data only, in a
couple of seconds per CVE, with no database and no paid API.
pip install git+https://github.com/scolly2683/cve-parser
cve-parser CVE-2026-111497
cve-parser CVE-2026-111497 --triage --json card.json # + static PoC triage
| # | Layer | Typical owner | Does the OS patch cover it? |
|---|---|---|---|
| 1 | OS package | base image / platform team | yes — this is the OS patch |
| 2 | Runtime engine (Node.js, Python, JVM…) | container image team | no — rebuild on a patched runtime |
| 3 | Bundled copy inside a runtime | container image team | no — the classic scanner trap |
| 4 | Language package (npm, PyPI, Maven, Go, crates…) | app team | no — wheels / jars carry their own copy |
| 5 | Code pattern / reachability | sets priority, not ownership | n/a |
| 6 | Runtime config (on or off by default) | app or platform team | n/a |
| 7 | Appliance / vendor product | network / platform owner | no — vendor patch |
| 8 | Endpoint software | endpoint team | no — push update |
Each layer says affected?, how to search for it, who owns it, whether it is on by default and what the fix is. The card also groups the work into four weekly-meeting lists (OS patches · tech-stack images · appliances/vendors · endpoints), lists the scanner traps between layers, and gives SBOM and code-search terms plus questions to ask the owning teams.
Excerpt (real output for cve-parser CVE-2026-115893, trimmed):
**bytecodealliance wasmtime — present at layer(s) 1, 4, 7; reachability (layer 5) UNKNOWN — priority undecided**
| # | Layer | Affected | Conf. | Owner | Fix |
| 1 | OS package | YES | medium | base image / platform team | OS patch + restart |
| 4 | Language package / library | YES | high | app team | dependency update + redeploy |
| 7 | Appliance / vendor product | YES | medium | network / platform owner | vendor patch |
- List 1 — OS patches: wasmtime OS package — rust-wasmtime
- List 2 — tech-stack images: app-team dependency bumps (layer 4): crates.io/wasmtime
For each public GitHub PoC repo it gives a safety screen (SAFE_TO_READ /
SUSPICIOUS / MALICIOUS) and a classification: target (stock product,
modified build or the author's own lab app), outcome, preconditions,
reliability, credibility and maturity. That comes out as a one-line verdict
such as:
[owner/repo] DoS crash on stock product. README claims RCE the code does not demonstrate. 0 stars, 1 commit. NOT an escalation trigger.
The per-CVE escalation trigger fires on code execution against an unmodified product that is corroborated (a credible source, or two independent authors), or a CISA KEV listing. One unverified repo is reported as an escalation candidate, never a trigger: a README can say anything.
- PoC code is never run, built, installed or imported. Triage is static only: it reads metadata and at most 10 small text files per repo, capped at 64 KB each. It never stores file bodies and never sends README text to an LLM, because a README is attacker-controlled text.
- Layer 1 ≠ layer 3. An OS patch is never assumed to fix a bundled copy.
- Layers 1–4 decide presence; only layer 5 decides priority. A CVE is never marked "not relevant" from layers 1–4 alone.
- No guessing from the description. Every evidence line carries its
source(cvelist | osv | redhat | ubuntu | kev | knowledge | inferred | lexicon | rule). - Every fetch is cached on disk (
CVE_PARSER_CACHE_DIR, default: the system temp dir), so re-runs are fast and polite.
All are fetched at runtime on your machine. This repo ships no third-party data. Check each provider's current terms before you redistribute output.
| Source | Used for | Terms |
|---|---|---|
| CVE List v5 | CNA record, affected products, CISA-ADP SSVC | CVE Program terms of use |
| NVD API 2.0 | fallback record, CVSS, CPE | public; this product uses the NVD API but is not endorsed or certified by the NVD |
| OSV.dev (follows GHSA / PYSEC / Bitnami aliases) | ecosystem packages, fixed versions | CC BY 4.0 (per-source licences apply) |
| Red Hat Security Data API | per-product package state | CC BY 4.0 |
| Ubuntu CVE API | per-package status + triage notes | Canonical's terms |
| FIRST EPSS | exploit probability | free; attribution requested |
| CISA KEV | known-exploited flag | public |
GitHub REST API (--triage only) |
PoC repo discovery + metadata | GitHub terms; set GITHUB_TOKEN for a usable rate limit |
Optional environment variables: GITHUB_TOKEN (strongly recommended with
--triage), NVD_API_KEY, CVE_PARSER_CACHE_DIR.
Feeds answer layers 1, 2, 4, 7 and 8 automatically. Layers 3 (bundled
copies), 5 (reachability) and 6 (config defaults) need curated knowledge:
one JSON file per root component in
src/cve_parser/knowledge/.
brotli.json is the reference.
A CVE without a knowledge file still gets a card, but layers 3, 5 and 6 come
back ? with an explicit gaps list rather than a guess.
Contributions of knowledge files are the most valuable thing you can add, especially for libraries that get bundled everywhere: OpenSSL, zlib, curl, libxml2, SQLite, expat, libwebp, libpng, Log4j.
- Alpha (0.2). One curated knowledge file today (Brotli). Every CVE whose record names a vendor and product now gets at least a layer-7 placement with versions and advisory (in a 189-CVE sweep, blank cards fell from 101 to 3); layers 3, 5 and 6 still need curation.
- Vendor / appliance / endpoint detection uses CPE part codes and a word
list. Each card says where its placement came from (
root_kind_source:lexicon,cpeorcvelist), so a low-confidence layer-7 row is easy to spot. - PoC verdicts are regex rules over text. They record why (
target_reason) and sayunstatedrather than guess reliability. They can still be wrong; the one-line verdict is a reading aid, not a decision. - The PoC triage does not check in-the-wild feeds (GreyNoise, VulnCheck KEV). CISA KEV is checked. The output says so.
- Without
GITHUB_TOKEN, GitHub allows 60 core calls an hour, which is enough for about one CVE's triage. If GitHub is unreachable, the triage says so; it never reports "no PoCs".
import asyncio
from cve_parser import build_card, gather_sources, render_markdown
sources = asyncio.run(gather_sources("CVE-2026-111497"))
card = build_card("CVE-2026-111497", sources) # pure function → dict
print(render_markdown(card))pip install -e ".[test]"
ruff check src tests
pytest -q
MIT, see LICENSE. An independent project, not affiliated with, sponsored by or endorsed by any company or organisation.