Skip to content

Kernel-CVE pipeline

The kernel-CVE pipeline looks at kernel vulnerabilities differently from a generic OS-CVE scanner: it talks directly to the distro trackers so a backport no longer shows up as a false positive.

Generic OSV/NVD matching produces floods of false positives on kernels: the upstream kernel reports “fixed in 6.11.5” while your distro (Debian 6.8.0-49, Ubuntu 6.8.0-49.49, RHEL 5.14.0-410, …) has already backported the fix into its LTS line. The pipeline matches per running release against that distro’s tracker:

What remains are the actual open kernel CVEs for your host: vulnerable (no fix in your kernel), patched (distro resolved it in your version, reboot required) or no-backport (distro decided not to patch, alternative required).

Inside ExtendedInventorySnapshot.kernel_inventory (visible in the Kernel tab on every agent detail page):

field source
running_release uname -r
running_version uname -v (build string)
last_boot_time /proc/stat btime
installed_kernels[] dpkg-query / rpm / pacman / qlist / apk
default_kernel /boot/grub/grubenv or grubby --default-kernel
reboot_required /var/run/reboot-required or dnf needs-restarting -r
mitigations_status /sys/devices/system/cpu/vulnerabilities/*
is_custom_build true when running release matches no installed package
kernel_cmdline /proc/cmdline

Older agent binaries send kernel_inventory: null; the hub-side worker silently skips those hosts: no false positives, no false negatives.

A KernelUpdateBatch is one operator decision (“patch CVE-2026-XXXX on every host with tag web-fleet”). The orchestrator (KernelUpdateOrchestratorWorker, every 60 s) splits that into:

  1. Canary: 10% of the selected hosts, max 3, min 1. Immediately receives a Level 3 EAT with update_kernel action. Phase tracked via kernel_update_progress.phase (queued → installing → installed → reboot_pending → rebooted_new).
  2. Primary: only activates after every canary host reaches rebooted_new. A single canary failure aborts the entire batch with an abort_reason.

Each EAT travels the same pipeline as manual actions: signing via MONSYS_EMERGENCY_PRIVATE_KEY, append-only transparency_log entry, persistent audit_log row.

The agent never runs as root. Kernel installs go through /usr/local/sbin/monsys-kernel-update with a specific sudoers rule:

monsys ALL=(root) NOPASSWD: /usr/local/sbin/monsys-kernel-update

The wrapper validates every argument itself (allowlist regex per package manager), snapshots the pre-install kernel set, runs the correct install (apt/dnf/zypper/pacman/portage), updates bootloader and initramfs, then writes /var/run/reboot-required so the hub picks it up on the next inventory cycle.

--reboot-strategy options:

  • none: operator reboots manually (default, safest)
  • manual: agent surfaces a banner; no action taken
  • auto-at-window: shutdown -r +5 (only inside a maintenance window)

Sources and the “patch pending” status

Section titled “Sources and the “patch pending” status”

The worker combines per distribution:

Distro Source What it yields
Ubuntu USN database patched or vulnerable with the fix version, per kernel flavor
Ubuntu CVE tracker (ubuntu.com/security/cves) high/critical kernel CVEs that have no package yet (needed/pending)
Debian security tracker (streamed, linux package only) open/resolved per suite; resolved only becomes patched when the running Debian version (from uname -v) reaches the fix version
RHEL/Gentoo CSAF / GLSA limited (see roadmap)

A CVE for which the distribution has not shipped the fix shows as vulnerable with pending 7.0.0-43.43 (the announced version) or no fix in archive yet in the patch available column. That is exactly the window in which you must mitigate yourself; this is how CVE-2026-98432 (MPTCP) surfaced on 2026-10-30 before Canonical had a USN. Suite and codename come from os-release (12 → bookworm, 26.04 → resolute); a backport kernel (~deb12u1) is checked against its own source package (linux-6.12). Debian CVEs with urgency unimportant are not recorded as findings.

Since this pipeline, patch_hygiene is a composite:

final = 0.7 × application_cves + 0.3 × kernel_currency

Kernel currency deductions (max −100):

  • each open vulnerable finding against the running release: −3 (cap −30)
  • reboot_required > 7 days: −15, > 30 days: −25
  • is_custom_build (no tracker visibility): −10
  • newer installed kernel than running (installed, not rebooted): −10

Hosts on a pre-pipeline agent are blanked (no score drop; UI shows “upgrade agent” hint).

The Monthly Audit Pack (see Monthly Audit Pack) gained four kernel emitters with this pipeline:

kind content
kernel_running per agent: current release, distro, reboot-required, last boot
kernel_cve_finding per month: every detected CVE with tracker source + distro status
kernel_reboot per month: every reboot with prev/new release + expected flag (EAT-driven or not)
kernel_update_batch per month: every orchestrator batch with canary/primary status + abort reasons

The PDF gains a dedicated “Kernel currency” section between the KEV CVE table and the Emergency Action Tokens log.

Migration 095 adds 7 controls (all draft until legal review):

  • NIS2 Art21 §2(e): kernel-CVE patching with canary + audit log
  • NIS2 Art21 §2(g): kernel currency hygiene (outdated kernels)
  • CRA AnnexI §6: secure kernel updates (Ed25519-signed)
  • CRA AnnexI §11, vulnerability handling, kernel (backport-aware)
  • CRA AnnexI §12: capability to deploy kernel patches
  • ISO 27001 A.8.8: detection (continuous tracker monitoring)
  • ISO 27001 A.8.8: patching cadence (vulnerable > 30 days)