Renames the product name in every user-visible surface and internal
self-reference: page title, nav/shell, login/MFA pages, email templates and
subject prefixes ([VULNCHECK] → [TRUEVULN]), TOTP issuer label, report/PDF
headers, notification previews, outbound User-Agent/HTTP-Referer headers we
set ourselves, docs (README, ARCHITECTURE, PROJECT_OVERVIEW, DATABASE_SCHEMA,
README.DEV, TROUBLESHOOTING is untouched — see below), and .env.example
placeholder config (LDAP/OIDC/SAML example domains and paths).
Also renamed the on-disk cache file paths (/tmp/vulncheck-*.zip|csv|json →
/tmp/truevuln-*), kept consistent across the two files that share the
cvelistV5 ZIP cache path — first run after deploy re-downloads that ~557 MB
cache once (harmless, disposable).
Deliberately LEFT UNCHANGED (not branding — real external references or
infra identifiers; renaming the text without renaming the underlying thing
would just break/mislead):
- The actual Gitea repo URL/path (gitea.isuit.ch/vulncheck/vulncheck) and the
README lines derived from it (git clone target dir, tree listing) — a real
repo rename is a manual Gitea-side step (Settings → repository name) the
user would need to do themselves, and existing clones would need
`git remote set-url` after.
- The real support mailbox (support-vulncheck.sq9vd@passmail.net, in both
README and TROUBLESHOOTING) and the Buy Me A Coffee link — both point to
accounts that still exist under the old name; renaming the text alone
wouldn't create new ones.
- GitNexus MCP resource URIs in CLAUDE.md/AGENTS.md (gitnexus://repo/
vulncheck/...) — tied to GitNexus's own index name for this repo, not our
branding; those files are untracked in this repo anyway.
- docker-compose.yml container/network/Postgres user+db names
(vulnmanager-*) — explicit user decision: infra naming carries real
deploy/data risk on an already-running instance and isn't part of the
product-branding ask.
- The Tailwind color token class `vulncheck-blue` (frontend/app/globals.css)
— invisible internal CSS variable name, renaming it would touch ~270
className occurrences for zero user-visible benefit.
Verified: backend py_compile clean on every touched .py file; frontend tsc
clean (two pre-existing, unrelated errors remain: assets/page.tsx SVG title
prop, mfa-setup missing qrcode.react types). All diffs are exact-string
renames — no other changes riding along.
Tester: M365 findings showed the synthetic placeholder description; the
CVSS-correction cascade (by design, for efficiency) never touches
title/description. Fill them separately from the authoritative source.
apply_real_cve_metadata(db, cve_ids): fetches the real CVE title + English
description from CVE.org cvelistV5 raw and writes them onto the M365
findings (first_detected_by='m365_check'), keeping a trailing note that
the finding originated from the Microsoft 365 Apps source (so the
provenance stays clear). Runs after CVSS-correction + enrichment in both
run_m365_check and run_m365_for_packages.
Verified live: CVE-2026-45456 → title "Microsoft Outlook and Word Remote
Code Execution Vulnerability" + the real type-confusion description.
Intune managed devices often run without a Wazuh agent, so their installed
software was invisible to EOL/M365 detection. Now the Intune sync reads
each device's detectedApps (Graph $expand=detectedApps) and runs them
through the existing detection.
- eol_service.run_eol_for_packages(db, asset, packages): source-agnostic
per-package EOL (endoflife.date → MS-lifecycle/exotics fallback), same
precedence as the eol-check endpoint.
- m365_service.run_m365_for_packages(db, asset, packages): source-agnostic
M365-Apps CVE detection (build-vs-channel) + real-metric correction.
- intune_service: detectedApps enrichment now on by default (toggle
"Detected apps (EOL/M365)" in the Intune settings card).
Findings are CVE-level, so OSV/MSRC/Ubuntu remediation enrichment and the
normal EPSS/KEV/date enrichment apply automatically. No migration.
Tester (follow-up to Plan P 45524f7): M365 Apps CVEs were created with a
placeholder severity=medium / cvss=None and a thin description. Pull the
real metrics straight away at check-in and clarify the description.
- After an M365 check creates/updates findings, run the CVSS-correction
cascade (vulnrichment → cvelistV5 → NVD) for the touched CVE ids, then
enrich_vulnerabilities (EPSS/KEV/EUVD + NVD dates). These are real CVE
ids, so they resolve like any other. The override path never touches
`description`, so the M365 source note is preserved.
- Description rewritten: states the affected product, installed vs fixed
build + "update via the Office channel", explains the detection source
(Wazuh syscollector build vs MS365 release notes — not in NVD/Wazuh),
and notes metrics come from MSRC + Vulnrichment/cvelistV5 with a pointer
to the MSRC remediation section.
No migration. CVSS/severity now populated on the next M365 Enrich run.
Tester: a CVE newly created by a sync appeared in the vuln list but left
NO initial audit entry ("new CVE detected on asset X at ...") — the audit
trail only began with the first status change (open -> patched etc.).
Confirmed: not intentional, simply never built; fails the revisionssicher
requirement.
- Migration 031: ALTER TYPE auditeventtype ADD VALUE
'VULNERABILITY_DETECTED' (idempotent, autocommit block).
- New app/services/audit_events.py: audit_new_vulnerabilities() writes one
System/Auto event per newly created finding:
"New finding detected: CVE-X on <hostname> (severity=..., source=...)".
- Wired into every creation path:
* Wazuh full sync (run_wazuh_vulnerability_sync) -> source=wazuh
* Wazuh per-agent sync (sync_agent_vulnerabilities, covers the
scheduler loop + per-asset rescan) -> source=wazuh
* Nessus sync (incl. Nessus EOL pseudo-vulns via
newly_created_vuln_ids) -> source=nessus
* endoflife.date upsert -> source=eol_check
* M365 Apps upsert -> source=m365_check
Full-sync and per-agent paths are independent (no double events).
- Best-effort: audit failure never breaks a sync.
Migration 031 required: alembic upgrade head.
Tester: M365 Apps security fixes never reach NVD and are invisible to
Wazuh's vulnerability detector — they only live on the Microsoft Learn
"Microsoft 365 Apps security updates" page. No Microsoft API exists.
New app/services/m365_service.py:
- fetch_security_data(): parse that page into monthly releases
(channel->build map + CVE list), cached 24h in settings.
- parse_build("16.0.19929.20172") -> (19929, 20172); compares the last
two dotted build segments numerically.
- channel_for_product(): tester's rule — name contains "enterprise" ->
Monthly Enterprise Channel, else Current Channel.
- detect_missing_cves(): installed >= newest channel build -> UNAFFECTED;
otherwise union the CVEs of every monthly section the host is behind.
- upsert_m365_vulnerability(): real-CVE rows (enrichable like any CVE),
placeholder severity refined by nightly enrichment / Correct-CVSS.
- run_m365_check(): walk Wazuh-linked assets, collapse per-language
duplicates, upsert.
Verified against the live page + tester's example: installed
16.0.19929.20172 vs MEC 19929.20162 -> UNAFFECTED (0 CVEs); an older
build -> the month's 15 CVEs. 92 releases parsed cleanly.
Wired up:
- POST /api/v1/vulnerabilities/m365-check (synchronous, RequireEditor).
- Nightly job m365_check_nightly at 03:20 UTC.
- "M365 CVEs" button on the vulnerabilities page.
No migration — uses existing vulnerabilities + settings tables.