-
Notifications
You must be signed in to change notification settings - Fork 0
ARCHITECTURE
PyCVE у цьому репозиторії побудований як static delivery pipeline:
-
rule-serviceбудує JSON rulesets для конкретних release - static HTTP server віддає ці файли
-
local-agentвизначає локальний дистрибутив і release -
local-agentзавантажує потрібний ruleset і виконує локальний match
У каталозі rules лежать тільки ті release-файли, які були реально згенеровані вибраним source і списком --releases.
Наприклад, каталог може містити:
focal.jsonjammy.jsonnoble.jsonbookworm.jsonbullseye.jsontrixie.jsoncve-priority.json
Релізні файли відповідають за applicability.
cve-priority.json відповідає за enrichment, сортування і display metadata.
Під час звичайного build-а в каталозі rules з’являються:
- один JSON ruleset на кожен release із
--releases - optional
cve-priority.json, якщо builder запускався з--write-priorityабо--priority-only
Під час довгого --canonical-cves fetch можуть тимчасово з’являтися:
canonical-feed.checkpoint.jsoncanonical-feed.checkpoint.json.records.jsonl
Семантика цих файлів:
-
canonical-feed.checkpoint.jsonМаленький status/meta checkpoint для resume. -
canonical-feed.checkpoint.json.records.jsonlAppend-only spool уже витягнутих Canonical CVE records.
Поведінка:
- після кожної успішно прочитаної сторінки checkpoint оновлюється
-
records.jsonlдозаписується, а не переписується цілком - при повторному запуску builder продовжує з останнього
next_offset - після успішного завершення checkpoint і spool видаляються
Якщо builder був зупинений або мережа впала:
- наявність цих двох файлів означає, що resume ще можливий
- їх не треба видаляти вручну, якщо ти хочеш продовжити незавершений прохід
Builder генерує один уніфікований ruleset format.
Top-level shape:
{
"version": "2026-05-13T19:24:59Z",
"generated_at": "2026-05-13T19:24:59Z",
"ttl": 3600,
"rules": []
}Shape одного rule:
{
"id": "CVE-2026-41205",
"platform": "ubuntu",
"release": "jammy",
"check_type": "package_version",
"operator": "lt",
"value": "1.1.3+ds1-2ubuntu0.2",
"code": 12345,
"message": "Host package mako is vulnerable to CVE-2026-41205",
"package_name": "mako",
"severity": "medium",
"references": [
"https://www.cve.org/CVERecord?id=CVE-2026-41205"
],
"source": "canonical-ubuntu-cves",
"match_mode": "version",
"rule_status": "fixed",
"fixed_version": "1.1.3+ds1-2ubuntu0.2",
"updated_at": "2026-05-13T19:24:59Z"
}Основні типи:
package_versionkernel_versionkernel_package_version
Основні режими match:
-
match_mode = "version"Це precise rules з comparator-based перевіркою. -
match_mode = "advisory"Це unresolved/unfixed CVE без published fixed version.
Для advisory rules:
-
operatorіvalueможуть бути відсутні -
fixed_versionзазвичайnull
match_mode |
rule_status |
Meaning |
|---|---|---|
version |
fixed |
Є published fixed version; агент робить точну version-based перевірку. |
advisory |
vulnerable |
Vendor still marks release/package/kernel track vulnerable; точного fixed cutoff ще немає. |
advisory |
pending |
Fix line already tracked, але published fixed version ще не вважається доступною для normal precise matching. |
Практично:
-
match_mode = "version"дає precise applicability verdict -
match_mode = "advisory"дає advisory/unfixed signal -
advisorymatches показуються за замовчуванням -
--fixed-onlyвідсікає advisory matches
Пріоритезація не визначає applicability. Вона працює поверх уже applicable findings.
Shape cve-priority.json:
{
"version": "2026-05-09T12:00:00Z",
"generated_at": "2026-05-09T12:00:00Z",
"ttl": 86400,
"cves": {
"CVE-2026-31431": {
"priority": "critical",
"is_kev": true,
"kev_date_added": "2026-05-02",
"epss_score": 0.9731,
"epss_percentile": 0.9992,
"published_at": "2026-04-29T00:00:00Z",
"updated_at": "2026-05-02T10:00:00Z",
"severity": "high",
"tags": [
"known_exploited",
"high_epss"
]
}
}
}Pipeline:
- з release rulesets витягуються CVE IDs
- формується
cve-priority.json - optional enrichment додає:
- KEV
- EPSS
- severity-derived priority
- optional manual overrides додають:
titleis_manual- найвищий display priority
Manual overrides можуть задаватися окремим JSON-файлом у простому вигляді:
{
"CVE-2026-31431": "copy.fail",
"CVE-2026-43284": {
"title": "dirtyfrag"
}
}Такі записи:
- отримують найвищий display priority
- позначаються як
is_manual = true - додають
title, який агент показує якCVE-... (title)
Priority policy:
- manual override має найвищий display priority
-
is_kev = true->priority = critical - дуже високий
EPSS->priority = high -
severity = high|criticalбез сильніших сигналів -> зазвичайpriority = medium -
severity = mediumабо recent-only signal ->priority = medium -
severity = low|negligible|unimportant->priority = low - якщо сильного сигналу немає, можливий
priority = unknown
Агент:
- матчить ruleset
- знаходить applicable CVE
- optional підтягує
cve-priority.json - сортує findings
- показує priority annotation і manual title
Очікувана поведінка при типових проблемах:
- якщо
cve-priority.jsonвідсутній: агент продовжує працювати без priority enrichment - якщо KEV або EPSS тимчасово недоступні:
builder продовжує формування
cve-priority.jsonбез відповідного enrichment - якщо Canonical feed відповідає повільно або timeout-иться:
builder для
--canonical-cvesне завершується одразу, а retry-ить і може продовжити через checkpoint - якщо Canonical fetch був перерваний: наступний запуск може продовжити з checkpoint
- якщо ruleset не вдається завантажити агентом: агент пробує використати локальний cache
- якщо cache протух і не дозволено
allow_expired_cache: агент повертаєERROR - якщо
dpkg-queryнедоступний: package/kernel-package checks не працюватимуть коректно, агент завершиться зERROR
Best-effort поведінка:
- enrichment layer може бути неповним
- applicability layer повинен залишатися джерелом істини
- мережеві проблеми не повинні змінювати саму семантику rules
У каталозі rules дозволено тримати поруч:
- release rulesets
cve-priority.json- manual priority JSON
Для --priority-only це безпечно, тому що builder сканує тільки JSON-файли з полем rules.
Через це:
-
cve-priority.jsonне буде помилково використаний як release ruleset - типовий
manual-priority-fileтеж не буде прийнятий за ruleset - у збір CVE для priority payload потрапляють тільки реальні applicability rules
-
cve-priority.jsonне додає CVE у findings без applicability match - manual
titleне означає, що CVE автоматично з’явиться у виводі -
priority = criticalне означає, що CVE застосовна до поточного хоста -
--priority-onlyне перебудовує release rules і не оновлює source feeds -
--ubuntu-ovalзавжди завантажує повний файл на кожен release - advisory rules не дають такої ж version precision, як
match_mode = "version"
PyCVE не є:
- exploit detector
- runtime EDR
- process scanner
- container/image scanner
- config auditor
PyCVE працює як applicability engine поверх:
- kernel version
- kernel package version
- installed package versions
- vendor security metadata
Тобто він відповідає на питання:
- чи стосується CVE цього хоста за наявними package/kernel даними
- чи є precise fixed cutoff або тільки advisory signal
- наскільки finding пріоритетний для відображення
Але він не відповідає на питання:
- чи CVE уже експлуатується саме на цьому хості
- чи конкретний сервіс реально reachable/exposed
- чи workaround/mitigation already applied поза package metadata
Для rule-service:
-
--canonical-cvesОсновний Ubuntu source. Paginated JSON API, ~70k CVE records для всіх releases в одному feed. Підтримує resume через checkpoint при перерваному fetch. -
--ubuntu-ovalАльтернативний Ubuntu source на основі Canonical OVAL XML feed. Завантажує окремий файл на кожен release (plain XML або.bz2). Дані еквівалентні--canonical-cvesза якістю і актуальністю. Кожен запуск завантажує повний файл. -
--debian-cvesDebian source.
PyCVE не прив’язаний до конкретного web stack. Потрібен лише static hosting каталогу з JSON-файлами.
Приклад мінімального nginx-конфіга:
server {
listen 8080;
server_name _;
root /usr/share/nginx/html;
location = /health {
default_type application/json;
return 200 '{"status":"ok"}';
}
location /rules/ {
try_files $uri =404;
}
location = / {
default_type text/plain;
return 200 'pycve static rules';
}
}