Safeguard
Supply Chain Security•

Linux Kernel CNA: How Kernel CVEs Are Assigned and What To Do

Since February 2024 the kernel assigns its own CVEs, one per fix in a supported stable tree. How the process works, the data, and how to triage thousands.

Safeguard Security Team
45 min read

The Linux kernel has been its own CVE Numbering Authority since February 2024. It assigns a CVE to almost every bug fix in a supported stable kernel, because almost any kernel bug might be exploitable, so kernel CVEs now number thousands a year. Stay on a supported stable kernel and filter by what you build.

The volume reflects a deliberate rule, not a worse kernel. This guide goes one level deeper than our look at Linux at 35: the assignment rule, the volume, where the records live, how stable kernels and distributions fit, and a pipeline for deciding which kernel CVEs matter to you. For filtering a single embedded build in depth, see our companion post on which kernel CVEs apply to an embedded device. Every figure below comes from a primary source linked under Sources, and the counts were pulled on 23 October 2026.

Key takeaways

  • The kernel.org CNA (CVE program ID CNA-2024-0016) was announced on 13 February 2024. Its scope, as listed by the CVE program, is any vulnerability in the Linux kernel as listed on kernel.org, excluding end of life versions. The first records from it appeared in the US National Vulnerability Database (NVD) on 20 February 2024.
  • The rule is simple and deliberately broad. A CVE is assigned only after a fix is in a released stable tree, it is tracked by the git commit of the original fix, and the team assigns one to "any bugfix that they identify" as potentially security relevant. Nothing is assigned for unfixed bugs or for kernel versions the stable team no longer supports.
  • Volume is real. NVD lists 4,287 non-rejected records from the kernel CNA published in 2024, 5,675 in 2025 and 7,856 in 2026 up to 22 October, with 4,590 in the third quarter of 2026 alone.
  • The authoritative data lives in two places: the linux-cve-announce mailing list and the vulns.git repository on git.kernel.org, which holds a JSON record, a human readable email, a list of fixing commits and a "dyad" file of vulnerable and fixed version pairs for every CVE, plus the tools that generate them.
  • Records include programFiles, the source files the fix touched. That one field is what makes config based filtering possible: if the file is not compiled into your kernel, the bug is not in your kernel.
  • Distributions re-triage everything. Red Hat rated only 157 of 5,761 kernel CVEs from 2025 as Important or Critical in its security data API; Debian's tracker and Ubuntu's priorities apply their own judgement per release. If you run a distribution kernel, its tracker is your source of truth, not the upstream version ranges.
  • For long lived products, two dates matter: kernel.org projects end of life for the 5.10 and 5.15 longterm branches in December 2026, and the EU Cyber Resilience Act's reporting obligations have applied since 11 September 2026, with its main obligations following on 11 December 2027.

When did the Linux kernel become a CVE Numbering Authority, and why?

A CVE Numbering Authority is an organisation the CVE program authorises to assign CVE identifiers and publish CVE records within a defined scope. Before 2024 kernel CVEs were assigned by whoever asked: distributions, researchers, other CNAs, and occasionally people whose reasons the kernel developers disputed.

The kernel's process document explains the motive in its first paragraph. It says CVE numbers "were very often assigned in inappropriate ways and for inappropriate reasons", that the kernel community had tended to avoid them as a result, and that continuing pressure plus "ongoing abuses by individuals and companies outside of the kernel community" made it clear the kernel community should control the assignments itself.

Greg Kroah-Hartman, one of the two stable kernel maintainers, announced the change on his blog on 13 February 2024. His post frames it as part of a trend of open source projects taking over the "haphazard assignments" of CVEs against their own code, names the curl and Python projects as earlier examples, and credits the OpenSSF for documentation and encouragement. He also links the decision to regulation: the work "looks like all open source projects might be mandated to do" under new laws, and having the process in place would let the kernel notify other CNA like organisations if needed.

The CVE program's own data confirms the details. The kernel's entry in the program's CNA list carries the short name "Linux", the organisation name kernel.org, the ID CNA-2024-0016, the contact address cve@kernel.org, and the linux-cve-announce archive as its advisory channel. Its top level root is MITRE. The HOWTO file in the kernel's vulns.git repository shows the CVE Services record for the kernel.org organisation with a creation timestamp of 14 February 2024.

DateEventSource
13 Feb 2024Greg Kroah-Hartman announces the kernel has been accepted as a CNAkroah.com, "Linux is a CNA"
14 Feb 2024kernel.org organisation record created in CVE Services (as shown in the vulns.git HOWTO)vulns.git HOWTO
20 Feb 2024First kernel CNA records published in NVD, including CVE-2023-52433 and CVE-2024-26581NVD API
Q2 20241,713 non-rejected kernel CNA records published in one quarterNVD API
10 Dec 2024EU Cyber Resilience Act enters into forceEuropean Commission
Q4 20251,809 records in the quarter, the highest so far at that pointNVD API
11 Sep 2026CRA reporting obligations for actively exploited vulnerabilities applyEuropean Commission
Q3 20264,590 records in one quarterNVD API
Dec 2026Projected end of life for longterm 5.10 and 5.15kernel.org releases page
11 Dec 2027CRA main obligations applyEuropean Commission

The kernel was not inventing the idea. It was joining a pattern where a project takes responsibility for identifiers in its own code so that no one else assigns them without involving the people who wrote the fix.

What is the kernel's rule for assigning a CVE to a fix?

The rules are short enough to quote in full in your own head, and they live at docs.kernel.org/process/cve.html. Here is what they say, paraphrased closely.

CVEs follow fixes, not reports. As part of the normal stable release process, developers on the CVE assignment team identify kernel changes that are potentially security issues and assign CVE numbers to them automatically. No CVE is automatically assigned for an unfixed issue. Assignment happens only after a fix is available and applied to a stable kernel tree, and the CVE is tracked by the git commit ID of the original fix.

Assignment is cautious on purpose. The document says that because of the layer the kernel sits at, almost any bug might be exploitable to compromise the kernel, and that the possibility is often not evident when the bug is fixed. So the team is "overly cautious" and assigns CVE numbers to any bug fix it identifies. The document itself says this explains the seemingly large number of kernel CVEs.

Only supported kernels. No CVE is assigned for an issue found in a kernel version that the stable and longterm team does not actively support. The list of supported branches is the kernel.org releases page.

Reserved IDs for embargoed work. If someone needs an identifier before a fix is committed, the team can hand out one from its batch of reserved IDs on request to cve@kernel.org. That alias is only for assignment questions; unfixed security bugs still go to the kernel security team through the normal reporting process.

Disputes belong to subsystem maintainers. The authority to dispute or modify a CVE for a given change lies solely with the maintainers of the affected subsystem.

Other CNAs' kernel CVEs are not valid. A CVE assigned against an actively supported kernel version by any group other than the kernel team "should not be treated as a valid CVE", and the team asks to be told so it can invalidate it through the CNA process. The flip side: if a bug exists only because of a distribution's own changes, or only in a distribution kernel based on a version kernel.org no longer supports, the kernel team cannot assign it and the distribution must.

Applicability is your job. This is the line most readers skip. The document says that the applicability of any specific CVE is up to the user of Linux to determine, that large numbers of assigned CVEs are not relevant to any given system because each system uses a small subset of the source tree, and, plainly, "we do not know your use case". It closes by recommending that users take all released kernel changes, because they are tested together, and warns that some relevant fixes will not have a CVE at all.

How does this fit with the kernel security team?

They are separate processes. The kernel's security bugs document says the security team "does not assign CVEs" and does not require them for reports or fixes, because that can complicate and delay bug handling. The security team focuses on getting fixes merged. When a reporter asks for a short embargo, publication of a fix may be held for up to 7 calendar days from the start of the release process, with an exceptional extension to 14 days. The CVE team works downstream of all that: once the fix ships in a stable release, it reviews the release and assigns identifiers.

How does the team decide which fixes count?

The vulns.git repository includes a voting_results script, written by Lee Jones, that "conducts voting" between reviewers over a git range of stable releases, with Greg Kroah-Hartman, Lee Jones and Sasha Levin named as primary reviewers. The practical picture is a small group reviewing each stable release's commits and agreeing which ones get an identifier.

How many kernel CVEs are published each year?

We counted three ways, because each answers a slightly different question.

By publication date, from NVD. We queried the NVD CVE API on 23 October 2026 for records whose source identifier is the kernel CNA, one calendar quarter at a time, with rejected records excluded. These are counts of records published in each window.

Quarter202420252026
Q15141,339644
Q21,7131,2041,917
Q31,0171,3234,590
Q41,0431,809705 (1 to 22 Oct)
Total4,2875,6757,856 so far

Including records that were later rejected, the totals are 4,443, 5,924 and 7,893. NVD's search includes rejected records unless you ask it not to, which is why the two sets differ.

By CVE ID year, from vulns.git. A shallow clone of the repository on 23 October 2026 contains 3,064 published records with 2024 IDs, 2,667 with 2025 IDs and 7,599 with 2026 IDs. It also holds 4,469 published records whose IDs carry the years 2021, 2022 and 2023, which reflects the team assigning identifiers to fixes from before it became a CNA. ID year and publication year are different things, so do not add these columns to the NVD table.

By where the fix landed. Each record lists the source files its fix touched. Counting the top level directory per record, about half of the 2025 and 2026 records touch drivers/ (50 percent and 49 percent), followed by net/ (15 and 20 percent) and fs/ (16 and 13 percent), with kernel/, arch/, include/, sound/ and mm/ in single digits. A record can touch more than one directory, so the shares do not add to 100.

That last table is the most useful one for triage. Half of all kernel CVEs are in drivers, and any one machine builds or loads only a small slice of the drivers tree. A server with no sound hardware does not care about sound/; a phone without a particular network card does not care about that card's driver.

What changed in the third quarter of 2026?

Volume jumped from 1,917 records in Q2 2026 to 4,590 in Q3. No primary source we found explains the step, so we do not attribute a cause. Operationally, reading every kernel CVE by hand stopped working long ago; filter by version and configuration first.

Where do the records come from?

There are two official outlets, and both come from the same tooling.

The linux-cve-announce mailing list. The kernel documentation names the list archive at lore.kernel.org/linux-cve-announce as the place where all assigned kernel CVEs are announced and invites anyone to subscribe. Each message is a plain text record: the description (usually the fix's commit message), an "Affected and fixed versions" block, the affected files, a mitigation note and links to the fixing commits. Note that lore.kernel.org now puts an automated proof of work check in front of scripted clients, so build your automation on the git repository rather than scraping the archive.

The vulns.git repository. At git.kernel.org/pub/scm/linux/security/vulns.git, this is the source of truth the emails and JSON are generated from. Its README says the repository tracks the identifiers reserved and assigned to the kernel project, and that the data is licensed under the CVE terms of use while the scripts and tools are GPL-2.0-only. Greg Kroah-Hartman's announcement warned that the structure "will change over time", so treat paths as stable in practice but not guaranteed.

Inside cve/ there are four state directories, defined in cve/README and cve/schema:

DirectoryMeaning
reserved/IDs allocated to the kernel CNA but not yet used, matching the RESERVED state in the CVE database
published/YEAR/Published CVEs, with their record files
rejected/IDs the team rejected because the issue was not a real one; the text explains why
returned/IDs that were reserved but never used, handed back so they do not count against the team's quota

Each published CVE has a set of files that share its ID as a prefix:

FileWhat it holds
CVE-YYYY-NNNNNThe original reserved placeholder, sometimes with notes
.sha1The git SHA-1 of the commit or commits that fix the issue
.jsonThe CVE JSON 5 record submitted to the CVE program
.mboxThe human readable email posted to linux-cve-announce
.dyadMachine readable pairs of vulnerable and fixed versions and commits, one line per stable branch
.vulnerable (optional)The commit that introduced the bug, used when the fix lacks a correct Fixes: tag
.message (optional)Replacement description text when the commit message is wrong or confusing
.reference (optional)Extra reference URLs
.cvss (optional)A CVSS v3.1 vector assigned by the kernel CNA, with per metric reasoning

The tooling sits in scripts/ and tools/. The names are worth knowing because you will see them in the records:

  • bippy generates the JSON and mbox for a CVE from a fixing commit. The mbox header you see on the mailing list starts with From bippy-1.2.0.
  • dyad takes a fixing commit and works out, for every supported branch, which release introduced the bug and which release fixed it. Its source comment calls it "VERY specific" to how the kernel labels its stable branches.
  • strak (Dutch for "tight") answers the question you actually have. Its built in help says strak --fixed 6.12.3 shows every CVE fixed in the 6.12.3 release, and strak v6.12.3 shows every CVE "currently vulnerable" in it.
  • cve_search finds the CVE, if any, for a given git commit.
  • cvss writes and checks the .cvss files.

How do you read a dyad line?

A dyad line has four colon separated fields: the version where the bug was introduced, the introducing commit, the version where it was fixed, and the fixing commit. A real record in the repository reads, in part:

2.6.27:f43798c27684ab925adde7d8acc34c78c6e50df8:6.12.113:32a8b0adaa18e52aaa0b246b5ffe683075354dbb
2.6.27:f43798c27684ab925adde7d8acc34c78c6e50df8:7.2.11:c3e33464746166264334641dc850a36eef7e6326
2.6.27:f43798c27684ab925adde7d8acc34c78c6e50df8:7.3:6785011f8b16abf40b1e9d8b2e332232b3e68822

Read that as: introduced in 2.6.27, fixed in 6.12.113 on the 6.12 branch, fixed in 7.2.11 on the 7.2 branch, and fixed in mainline 7.3. A line whose fixed side is 0:0 lists no fix on that line yet, which is what you will see when a bug was introduced in a branch the fix has not reached.

How do you read the JSON record?

The JSON follows the CVE 5 schema and is generated, not hand typed. The fields that matter for triage are under containers.cna:

  • descriptions: usually the fix's commit message, prefixed with "In the Linux kernel, the following vulnerability has been resolved".
  • affected[]: two kinds of entries. One expresses ranges as git commits and stable versions marked affected, for example 6.6.51 up to but not including 6.6.133. The other has defaultStatus set to affected and then lists unaffected ranges such as everything before the introducing release, 6.6.133 through the rest of 6.6.*, and everything from the mainline fix onward.
  • programFiles: the source files the fix touched, for example fs/xattr.c.
  • cpeApplicability: CPE match ranges, for tools that only understand CPE.
  • metrics: present when the CNA scored the issue, carrying the CVSS v3.1 vector and, where it fits within 4,096 characters, the reasoning.

The mbox version says the same thing in prose, and adds two things worth reading: a note that "Unaffected versions might change over time as fixes are backported", and the mitigation paragraph recommending the latest stable kernel.

Does the kernel CNA publish CVSS scores?

For some records, yes. The repository's schema documents an optional .cvss file: the first line holds the scoring CNA's organisation ID and a CVSS v3.1 vector, the numeric score is computed from the vector rather than stored, and after a blank line comes one paragraph of reasoning per metric. The schema is explicit that not every CVE gets one and that "a missing .cvss file is a decision and not a gap". On 23 October 2026, 1,060 of the 2,667 records with 2025 IDs and 3,014 of the 7,599 records with 2026 IDs carried a .cvss file.

Two cautions. First, a CNA score describes the worst plausible case the scorer considered for the upstream code; it does not know your configuration any more than the assignment team does. Second, NVD and distributions may publish their own scores for the same CVE, and they often differ. Record which source a score came from whenever you store one.

How do stable and longterm kernels relate to CVE fixes?

The kernel has four kinds of releases, defined on kernel.org's releases page:

KindWho maintains itCadence and purpose
Prepatch (rc)Linus TorvaldsPre-releases for testing new features
MainlineLinus TorvaldsA new release every 9 to 10 weeks; all new development lands here
StableStable maintainersBug fixes backported from mainline, released as needed, usually weekly, until the next mainline release
LongtermStable maintainersSelected releases that keep receiving important backported fixes for years

On 23 October 2026, kernel.org listed 7.3 as both the latest mainline and the latest stable release, 7.2.12 as the latest 7.2 stable, and six longterm branches:

Longterm branchFirst releasedProjected EOLLatest on 23 Oct 2026
6.1830 Nov 2025Dec 20286.18.58
6.1217 Nov 2024Dec 20286.12.114
6.629 Oct 2023Dec 20276.6.160
6.111 Dec 2022Dec 20276.1.190
5.1531 Oct 2021Dec 20265.15.223
5.1013 Dec 2020Dec 20265.10.272

The releases page notes that projected EOL dates "are not set in stone": each longterm kernel usually starts with a two year projection that can be extended if industry helps support it.

Three consequences follow for CVE handling.

A fix reaches you through a stable release. The stable kernel rules require that a patch, or an equivalent fix, already exists in mainline before it goes into a stable tree. So the usual order is: fix merged in mainline, backported to the stable and longterm branches where it applies, released, then assigned a CVE. The dyad file records exactly which release on each branch carried it.

End of life ends the records. Because no CVE is assigned for kernels the stable team no longer supports, once 5.10 and 5.15 reach end of life their branches stop appearing in new dyad files. A fix to a bug that also exists in 5.10 will be recorded against the supported branches only. If you ship 5.10 after that, nobody upstream will tell you whether a new CVE affects you.

"Use a supported stable kernel" is the core advice, not a slogan. The CVE documentation says it is best to take all released changes because they are tested together, and that many bugs are fixed by the sum of several changes. The mitigation section of every CVE email goes further: individual changes are never tested alone, and cherry picking is not recommended or supported. Picking twenty commits out of a thousand to address twenty CVEs gives you an untested kernel that still lacks the fixes nobody gave a CVE.

What if you run a distribution kernel?

Distribution kernels have their own version numbers and their own patch sets. An Ubuntu kernel such as 6.8.0-xx-generic or an enterprise kernel based on an older upstream release is not the upstream 6.8 branch, which reached end of life long ago upstream. The kernel's documentation addresses this directly: issues that exist only because of distribution changes, or only in distribution kernels based on versions kernel.org no longer supports, are the distribution's to assign and fix. In practice that means the distribution's tracker, not the upstream dyad, tells you whether your installed kernel package is fixed.

How do distributions triage kernel CVEs differently?

Every major distribution receives the same upstream flood and runs its own assessment on top of it. They differ in vocabulary, in what they publish, and in how much they defer.

Ubuntu assigns each CVE an Ubuntu priority (Critical, High, Medium, Low, Negligible) that its CVE pages say is distinct from CVSS scores, its own or anyone else's. Low means "a security problem, but hard to exploit due to the environment", among other conditions, and Low issues tend to ship only when higher priority fixes need an update or many low issues have built up. Negligible issues typically will not receive updates unless an easy fix rides along with something else. Per release, each package gets a status: Needs evaluation, Not affected, Vulnerable, Vulnerable with work in progress, Vulnerable with fix deferred, Fixed, Ignored or Not in release. Ubuntu's kernel lifecycle page shows why the same CVE can have different answers across releases: Ubuntu 26.04 LTS shipped on a 7.0 kernel in April 2026 with standard security maintenance until May 2031, Expanded Security Maintenance until May 2036 and legacy add-on coverage until May 2041, while 24.04 LTS started on 6.8.

Debian tracks every kernel CVE against the linux source package for each suite in its public security tracker. On 23 October 2026, the tracker's page for linux listed 1,955 open issues, 63 open issues marked unimportant and 18,392 resolved issues. Of the open ones, bookworm (Debian 12) showed 1,688 as vulnerable and 250 already fixed in that suite, plus 11 marked no DSA and ignored and 4 marked no DSA and postponed; trixie (Debian 13) showed 742 vulnerable and 1,211 fixed; forky and sid showed 21 vulnerable. The older stable suite carries far more open kernel items, which is what you would expect when the fixes arrive through newer upstream releases first. For what each status means, see our guide to Debian security tracker statuses.

Red Hat rates each CVE on its four point scale (Critical, Important, Moderate, Low) against its own products. Its public security data API, queried on 23 October 2026 for the kernel package with public dates in 2025, returned 5,761 CVEs: 1 Critical, 156 Important, 3,049 Moderate, 1,260 Low and 1,295 without a rating in the API response. That is fewer than 3 percent at Important or above.

QuestionUbuntuDebianRed Hat
Severity vocabularyPriority: Critical, High, Medium, Low, NegligiblePer suite status, with markers such as no DSA, postponed, ignored and unimportantImpact: Critical, Important, Moderate, Low
Uses upstream CVSS directly?No; priority is separate from CVSSNo; tracker status is per suiteNo; rates against its own builds
Per release answerStatus per package per releaseStatus per suiteStatus per product and stream
Machine readable dataCVE data exports and OVAL feedsTracker JSONSecurity data API
Where to read the fix versionCVE page and USNTracker page and DSA or DLACVE page and errata

For how Ubuntu's notices and OVAL feeds work in detail, see how Ubuntu security notices and OVAL data work.

The practical lesson is simple. The upstream record tells you which upstream releases are fixed. Your distribution's tracker tells you which installed package is fixed, and how urgent the distribution thinks it is for its default configuration. Use the tracker for distribution kernels, the upstream data for kernels you build yourself, and do not compare a distribution's priority with an NVD score as if they measured the same thing.

How do you decide which kernel CVEs matter for your build?

You narrow the list in three passes: version, configuration, then exposure. Each pass is mechanical enough to automate, and each removes a large share of the noise. Our embedded device post walks through the same idea for one product image; here is the fleet version.

Pass 1: version. Is your kernel inside an affected range for this CVE? The JSON's affected entries and the dyad lines answer that. If you are on a current release of a supported branch, most CVEs published this week are already fixed in your kernel, because the CVE was assigned after the stable release that fixed it shipped. The open set is what was fixed in releases newer than yours.

Pass 2: configuration. Is the code in your kernel at all? Use programFiles. If none of the .c files the fix touched were compiled for your build, the bug is not in your binary. Kernel builds leave an object file next to every compiled source file in the build output directory, so the check is literal: does fs/smb/server/smbacl.o exist in your build tree? For distribution kernels you do not build, the equivalent is the shipped config (/boot/config-$(uname -r) or /proc/config.gz) and the module list.

There are limits. Fixes in headers under include/ affect everything that includes them, so keep those. Some fixes touch core files that are always built. And a file being compiled is not the same as it being reachable, which is pass 3.

Pass 3: exposure. Of what remains, what can an attacker reach on this machine? Questions that move a CVE up or down:

  • Is the module loaded, or can an unprivileged user cause it to load (for example by opening a socket of a given family)?
  • Is the subsystem reachable from the network, from an unprivileged local user, from inside a container, or only from root?
  • Do you run untrusted code: multi-tenant containers, CI runners, browser sandboxes, guest VMs?
  • Does the hardware exist on the machine? A driver for a device you do not have usually needs physical access or a malicious device to reach.

Pass 3 is judgement, and it is where the kernel team says it cannot help: it does not know your use case. Write the answers down per host class, not per CVE, and reuse them.

A decision table for one kernel CVE

What you foundWhat to do
Your kernel version is outside every affected rangeRecord "not affected, version" and move on
Affected version, but none of the programFiles are builtRecord "not affected, code not present"; keep the evidence (config and object list)
Affected, code built as a module that is not loaded and cannot be autoloaded by unprivileged usersSchedule into the next routine kernel update; consider blocking the module now
Affected, built in or loadable, reachable by an unprivileged local userTreat as a local privilege risk; prioritise on multi-user, container and CI hosts
Affected and reachable from the network or from a guest or container boundaryUpdate now; use live patching or a mitigation while you schedule reboots
Listed in CISA's Known Exploited Vulnerabilities catalogUpdate now regardless of the other rows, and check the catalog's due date if it applies to you
Distribution kernelUse the distribution tracker's status and fixed package version instead of upstream ranges

Step by step: a kernel CVE triage pipeline

This walkthrough builds a small, repeatable pipeline from the kernel's own data. It is a triage aid, not an authority: when it disagrees with the official record or your distribution's tracker, they win.

1. Inventory the kernels you run

Collect the running kernel version and, where you can, the config from every host class. On a single machine:

uname -r
cat /proc/version
# Distribution kernel packages
dpkg -l 'linux-image*' 2>/dev/null | awk '/^ii/{print $2, $3}'   # Debian, Ubuntu
rpm -q kernel 2>/dev/null                                         # RPM based
# The config the running kernel was built with
ls /boot/config-"$(uname -r)" 2>/dev/null || zcat /proc/config.gz | head
# Loaded modules
lsmod | sort | head -50

Across a fleet, group hosts by uname -r and run the rest of the pipeline once per distinct kernel, not once per host. Mark each kernel as either "upstream build" (you compile it from kernel.org or a vendor tree you control) or "distribution package". Only upstream builds go through steps 3 to 5; distribution packages go to step 6.

2. Get the kernel's CVE data

git clone https://git.kernel.org/pub/scm/linux/security/vulns.git
# Later, to refresh:
git -C vulns pull --ff-only
# How many published records per ID year
for y in vulns/cve/published/*/; do printf '%s %s\n' "$y" "$(ls "$y" | grep -c '\.json$')"; done

A full clone is large. A shallow clone with --depth 1 is enough for the record files if you do not need history.

3. Look up a single CVE

id=CVE-2025-22038
f=$(ls vulns/cve/published/*/"$id".json)
jq -r '.containers.cna.descriptions[0].value' "$f" | head -5
jq -r '.containers.cna.affected[].programFiles[]?' "$f" | sort -u
cat "${f%.json}.dyad"

That record's affected file is fs/smb/server/smbacl.c, which is part of ksmbd, the in-kernel SMB server. If you do not build ksmbd, pass 2 removes it. To see which config symbol controls a directory in your own source tree, read its Makefile:

grep -n 'obj-' fs/smb/server/Makefile

and check that symbol in your .config. Reading your own tree is better than trusting a symbol name from a blog post, because Kconfig names do change between releases.

4. Use the kernel's own tool for "what is still open in my version"

If you build from a kernel git tree, strak is the purpose built answer. The tools are written in Rust and built from the tools/ directory, and they need a full linux-stable checkout for git lookups. Check each tool's help output for the current options, since the repository warns its structure may change.

cd vulns/tools && cargo build --release && cd ../..
# Point the scripts at a full linux-stable clone (see the repository HOWTO)
export CVEKERNELTREE="$HOME/src/linux-stable"
vulns/scripts/strak --help
vulns/scripts/strak v6.12.110          # CVEs still vulnerable in 6.12.110
vulns/scripts/strak --fixed 6.12.114   # CVEs fixed in 6.12.114

The difference between the two lists for your current release and the latest release on your branch is, in one line, the security case for updating.

5. Filter by version and by what you built

When you cannot run strak, or you want the configuration pass in the same report, a short script over the JSON records does both. It evaluates the affected ranges for your version and then checks whether any .c file in programFiles produced an object file in your build output directory.

#!/usr/bin/env python3
# kernel_cve_triage.py: triage aid over vulns.git JSON records.
# Usage: python3 -I kernel_cve_triage.py VULNS_DIR KERNEL_VERSION BUILD_DIR > report.tsv
import glob, json, os, sys

vulns, mine_s, build = sys.argv[1], sys.argv[2], sys.argv[3]

def ver(s):
    parts = []
    for p in s.split("."):
        if not p.isdigit():
            break
        parts.append(int(p))
    return tuple(parts + [0] * (3 - len(parts)))

mine = ver(mine_s)

def in_unaffected(v):
    start = ver(v["version"]) if v["version"] != "0" else (0, 0, 0)
    if "lessThan" in v:
        return start <= mine < ver(v["lessThan"])
    lte = v.get("lessThanOrEqual")
    if lte == "*":
        return mine >= start
    if lte and lte.endswith(".*"):
        return mine[:2] == start[:2] and mine >= start
    return mine == start

def affected(rec):
    entries = rec["containers"]["cna"].get("affected", [])
    for e in entries:  # explicit affected semver ranges win
        for v in e.get("versions", []):
            if v.get("status") == "affected" and v.get("versionType") == "semver" and "lessThan" in v:
                if ver(v["version"]) <= mine < ver(v["lessThan"]):
                    return True
    for e in entries:  # default affected, minus unaffected ranges
        if e.get("defaultStatus") == "affected":
            if not any(v.get("status") == "unaffected" and in_unaffected(v) for v in e.get("versions", [])):
                return True
    return False

def built(files):
    srcs = [f for f in files if f.endswith(".c")]
    if not srcs:
        return "review"  # headers, assembly, Rust or no file list
    hits = [f for f in srcs if os.path.exists(os.path.join(build, f[:-2] + ".o"))]
    return "built" if hits else "not-built"

print("cve\tstatus\tbuilt\tcvss\tfiles")
for path in sorted(glob.glob(os.path.join(vulns, "cve/published/*/*.json"))):
    rec = json.load(open(path))
    if not affected(rec):
        continue
    files = sorted({f for e in rec["containers"]["cna"].get("affected", []) for f in e.get("programFiles", [])})
    cvss = ""
    for m in rec["containers"]["cna"].get("metrics", []):
        if "cvssV3_1" in m:
            cvss = str(m["cvssV3_1"].get("baseScore", ""))
    cve = os.path.basename(path)[:-5]
    print(f"{cve}\taffected\t{built(files)}\t{cvss}\t{','.join(files)}")

Run it against the upstream version you build and the output directory of that build:

python3 -I kernel_cve_triage.py ./vulns 6.12.110 ~/build/linux-6.12-myboard > report.tsv
awk -F'\t' 'NR>1{print $3}' report.tsv | sort | uniq -c
awk -F'\t' '$3=="built"' report.tsv | sort -t$'\t' -k4,4nr | head -40

The first command shows how many affected CVEs touch code you built, code you did not build, and records that need a human look. The second lists the built ones, highest CNA score first where one exists. The rows marked not-built are your evidence for "not affected, code not present", which is worth keeping for an auditor or a customer questionnaire. The script deliberately treats anything it cannot decide as review rather than guessing.

6. For distribution kernels, ask the distribution

# Debian: open kernel issues for your suite, from the tracker's JSON
curl -s https://security-tracker.debian.org/tracker/data/json -o debian.json
jq -r '.linux | to_entries[] | select(.value.releases.bookworm.status=="open") | .key' debian.json | wc -l

# Red Hat: kernel CVEs since a date, with Red Hat's own severity
curl -s 'https://access.redhat.com/hydra/rest/securitydata/cve.json?package=kernel&after=2026-09-01&per_page=1000' \
  | jq -r '.[] | [.CVE, .severity] | @tsv' | sort -k2 | head

# Ubuntu: check a CVE's per release status on its CVE page, or consume the OVAL feeds

Then answer the operational question the trackers answer best: is there a newer kernel package for my release, and am I running it?

apt list --upgradable 2>/dev/null | grep -E '^linux-(image|generic)'   # Debian, Ubuntu
dnf check-update kernel 2>/dev/null                                     # RPM based
# After installing, confirm the running kernel changed
uname -r

A kernel package installed but not booted fixes nothing. Track "installed" and "running" separately, or use live patching where your distribution supports it and record which fixes it covers.

7. Stop gaps while you schedule a reboot

If a reachable CVE sits in a module you do not need, blocking the module is a reversible mitigation. Check the module name on your system before you write the rule:

modinfo ksmbd 2>/dev/null | head -3
lsmod | grep -w ksmbd
# Block loading on the next attempt (reversible: delete the file)
echo 'install ksmbd /bin/false' | sudo tee /etc/modprobe.d/disable-ksmbd.conf

This does not unload a module that is already loaded and in use, and it is not a fix. It narrows exposure until the updated kernel is running.

8. Automate it weekly

Run the pipeline on a schedule so the report follows the data. A minimal GitHub Actions workflow for a product that pins one upstream kernel version:

name: kernel-cve-triage
on:
  schedule:
    - cron: "0 6 * * 1"
  workflow_dispatch: {}
jobs:
  triage:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Fetch kernel CVE data
        run: git clone --depth 1 https://git.kernel.org/pub/scm/linux/security/vulns.git
      - name: Download last kernel build output
        run: ./ci/fetch-kernel-build.sh build   # your own script: object files from the last product build
      - name: Triage
        run: python3 -I tools/kernel_cve_triage.py vulns "$(cat kernel.version)" build > report.tsv
      - uses: actions/upload-artifact@v4
        with:
          name: kernel-cve-report
          path: report.tsv

Keep the workflow's job narrow: produce the report. The decision to rebase onto a newer stable release belongs to a person who has read the built and reachable rows.

What does this mean for embedded and long lived products?

Embedded products feel the rules hardest. A device often outlives its longterm branch, and after end of life the kernel CNA stops recording fix status for that branch, so the device maker, the silicon vendor or a longer term maintenance effort must carry the tracking. Vendor kernels add out of tree patches that upstream records cannot describe, and the kernel documentation says issues introduced by such changes are not the kernel CNA's to assign.

Regulation adds pressure. The Cyber Resilience Act has applied its reporting obligations since 11 September 2026: manufacturers must report actively exploited vulnerabilities in their products with digital elements. The main obligations, including the vulnerability handling requirements, apply from 11 December 2027. The European Commission published practical guidance for manufacturers on 27 July 2026. A device maker that cannot say which kernel CVEs affect a shipped firmware image will struggle with both.

The Civil Infrastructure Platform (CIP), a Linux Foundation project, exists for exactly this gap. CIP provides Super Long Term Stable (SLTS) kernels with a ten year maintenance period, built in collaboration with the kernel community. The SLTS kernels start from standard longterm kernels and extend them; the scope of support (subsystems, drivers, features) is agreed between CIP members and the CIP kernel maintainers, who track fixes queued for active longterm kernels and select the ones to backport. CIP also maintains core userspace packages based on Debian for at least ten years. Its cip-kernel-sec project tracks CVE status across mainline, stable and configured branches, imports data from Debian's and Ubuntu's trackers, and reports which issues affect which branch. For the background, see our explainer on the Civil Infrastructure Platform.

For a product team, the practical plan is:

DecisionRecommendation
Kernel baseA longterm branch with the longest remaining projected life, or a CIP SLTS kernel when you need a decade
UpdatesRebase onto new stable or SLTS releases on a fixed cadence; avoid cherry picking individual CVE fixes
ConfigurationBuild a minimal config; every driver and protocol you leave out removes its CVEs from your list
EvidenceKeep the config, the build's object list and the triage report per released image
Field updatesShip a signed update mechanism that can replace the kernel, and test it before you need it
After upstream EOLName who tracks fixes (CIP, your silicon vendor or your own team) before the date arrives

Common mistakes

Counting raw CVEs as a risk metric. A dashboard that shows "2,000 kernel CVEs" for a fleet says more about the kernel's assignment rule than about your exposure. Report the built and reachable subset, and the age of the running kernel against the latest release on its branch.

Cherry picking the fixes that have CVEs. The kernel team says not to, the mitigation text in every record says not to, and it leaves out related fixes that never got an identifier. Take whole stable releases.

Applying upstream version ranges to a distribution kernel. 6.8.0-xx-generic is not upstream 6.8.xx. Use the distribution tracker for distribution packages.

Treating a CVSS number as the priority. The CNA's score, NVD's score and your distribution's rating each assume different things. A 7.8 in a driver you do not build is a zero for you.

Assuming containers isolate you from kernel CVEs. Containers share the host kernel. A kernel bug reachable from inside a container is a host problem, and updating a container image does nothing for it.

Installing but not rebooting. The package manager says fixed; uname -r says otherwise. Track the running kernel.

Ignoring end of life. A branch past end of life stops getting new fix information from the kernel CNA. Silence after that date is not safety.

Throwing away the "not built" evidence. "Not affected because the code is not compiled in" is a strong answer, but only if you can show the config and the object list for the exact build you shipped.

FAQ

Why does the Linux kernel have so many CVEs?

Because the kernel's CVE team assigns one to almost every bug fix in a supported stable release that could plausibly be security relevant. Its documentation says the team is "overly cautious" since almost any kernel bug might be exploitable and that is often not clear when the fix is made. The count reflects the rule, not a sudden drop in quality.

When did the Linux kernel become a CNA?

Greg Kroah-Hartman announced it on 13 February 2024, and the first records from the kernel CNA appeared in NVD on 20 February 2024. The CVE program lists it as kernel.org, short name Linux, ID CNA-2024-0016.

Does the kernel CNA assign CVEs before a fix exists?

Not automatically. The rule is that a CVE is assigned after a fix is available and applied to a stable tree. Someone who needs an identifier earlier can ask cve@kernel.org for one from the team's reserved batch.

Where can I download all Linux kernel CVEs?

Clone vulns.git from git.kernel.org/pub/scm/linux/security/vulns.git. Each published CVE has a JSON record, an email version, the fixing commit IDs and a dyad file of vulnerable and fixed versions. You can also subscribe to the linux-cve-announce mailing list.

How do I check which kernel CVEs affect my kernel version?

For a kernel you build from upstream, the kernel's strak tool lists CVEs still vulnerable in a given release, or you can evaluate the JSON affected ranges yourself. For a distribution kernel, use the distribution's security tracker and its fixed package versions.

Does the Linux kernel CNA give CVSS scores?

For some records. The vulns.git schema documents an optional .cvss file with a CVSS v3.1 vector and per metric reasoning, and says a missing file is a decision rather than a gap. On 23 October 2026 about 40 percent of records with 2025 and 2026 IDs had one.

Should I cherry pick kernel CVE fixes into my kernel?

The kernel community says no. Its CVE records state that individual changes are never tested alone and that cherry picking is not recommended or supported. Update to the latest release on a supported stable or longterm branch instead.

Can a CVE be assigned for an end of life kernel?

Not by the kernel CNA. Its documentation says no CVEs are assigned for issues in versions the stable team no longer supports. Issues in a distribution's kernel based on such a version must be handled by that distribution.

How do embedded devices handle kernel CVEs over ten years?

By choosing a long maintained base, such as a longterm branch or a CIP Super Long Term Stable kernel with a ten year maintenance period, building a minimal configuration, rebasing on new releases rather than cherry picking, and keeping per build evidence of what is compiled in.

Where Safeguard fits, honestly

Safeguard does not read your kernel config, does not decide which kernel CVEs are reachable in your kernel build, and does not patch or live patch host kernels. That triage is work you do with the kernel's own data, your distribution's tracker and the pipeline above. A container image scan does not see the host kernel at all, because containers do not carry one. Where Safeguard helps is the rest of the software on those same machines: it scans repositories, container images and SBOM files (safeguard scan --dir ., --image <name>, --sbom <file>), matches components against vulnerability databases, ranks findings with reachability analysis, shows which projects contain a given component and version, and evaluates policies and gates before a build ships.

A kernel update rarely travels alone. The same rebuild that moves a device or a host to a new stable kernel also pulls new userspace packages, libraries and container base images, and those ship open source components with their own CVEs and their own fix releases.

Fix it without waiting for upstream

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

To be plain about scope again: none of these demos triage kernel CVEs. They show how Safeguard handles the application dependencies and images that sit on top of the kernel, which is the part of a fleet update that Safeguard does cover.

This first demo is a real CLI session. You install the CLI, run safeguard to open the interactive terminal and ask it to fix a lodash CVE; it reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. The same ask before every command flow applies when you point it at the repository that builds the services you redeploy after a kernel update.

Click through it at your own pace, or open it full screen.

The second demo sets up the local runner on your own machine: you approve it with its device code, then scan from the terminal. That suits a build host where you assemble device images or base container images and would rather the scan run where the files already are.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and lets you choose which tools Claude can use. If your team already uses Claude to work through patch planning, this is how to let it ask Safeguard which of your projects carry a given package version, with only the tools you approve.

Click through it at your own pace, or open it full screen.

You can download Safeguard or read the CLI documentation to try it on your own build.

Quick check

A new kernel CVE lists fs/smb/server/smbacl.c as its only affected file. Your build output has no fs/smb/server directory. Are you affected?

Not by that bug in that build. The code the fix touched was never compiled into your kernel. Record it as not affected because the code is not present, and keep the config and object list as evidence. Re-check if you later enable the SMB server.

Why does the kernel CNA tell you to update to the latest stable release instead of applying the one commit that fixes a CVE?

Because stable releases are tested as a whole, many problems are fixed by several commits together, and some security relevant fixes never get a CVE. Cherry picking leaves you with an untested combination that still misses those fixes.

Sources

Last reviewed: 23 October 2026. Kernel CVE counts, supported branches and distribution statuses change weekly; check the linked sources for current figures.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.