Gauging real-world exposure of Linux kernel bugs with Netlas

Sizing exposure for network-reachable kernel bugs with Netlas scan queries. Counts from November 2026.

When a kernel bug gets a CVE number, the first question every maintainer, distro security team, and CISO asks is the same one: how many machines can this actually touch? This article is my workflow for estimating that with internet-wide scan data, using Netlas.

Methodology up front. All counts in this article were taken in November 2026 against the default responses index, which Netlas keeps updated in real time; sampled records carried scan label 2026-10-23 at collection time. Netlas counts matching response records, not unique machines: one host can appear many times, and counts above 1,000 are estimates with a stated error margin of up to 3 percent. Where this article says hosts, read it as scan records unless it says otherwise. Disclosure as agreed with Netlas.

The headline results, before the method:

  • 401,310,508 HTTP response records, one visible slice of TCP-facing services.
  • 608,395 SMB response records, the candidate set for any ksmbd exposure question.
  • About 10.9 million SSH records carrying an Ubuntu or Debian banner, a measured candidate set for Linux version exposure.
  • In the vulnerability index, a kernel CVE can return zero records (coverage gap) or 32.8 million (product fingerprint). Both extremes describe the index, not the vulnerability.

Why exposure data matters when triaging a kernel bug

I fix kernel bugs upstream. Twenty-six of my fixes have CVE numbers now, and they split into very different exposure classes. The hp-bioscfg bugs need local access to specific sysfs attributes on HP hardware. The Bluetooth ISO races need a paired or connecting peer in radio range. The rtl8723bs wifi bugs need an attacker within radio distance. None of those will ever show up in an internet-wide scan, and that is fine: their exposure ceiling is small by construction.

But the kernel also runs servers that listen on public IP addresses, and underneath all of them sits the TCP/IP stack itself, which parses attacker-supplied packets on every Linux host on the planet. When a bug lands in code like that, severity alone does not tell you what to do. Two bugs with identical CVSS scores can differ by five orders of magnitude in reachable infrastructure.

Exposure measurement adds a dimension to triage. It does not replace severity analysis, and a large population does not make a bug technically worse, but it tells a security team the scale of potentially affected infrastructure. I wrote elsewhere about the scoring fight over CVE-2026-80603, my netfilter IRC helper fix, where the kernel CNA said 9.1 Critical and Red Hat said 5.3 Moderate. Neither score is wrong. An exposure estimate is a third kind of statement, about how much infrastructure can receive the relevant traffic, and it belongs in the conversation next to the score rather than instead of it.

Which kernel components are reachable from the network

Before querying anything, I sort the bug into a reachability class. This is the list I work from, widest first:

  • The kernel network stack itself: IPv4, TCP, and every parser under them. The worked example below is CVE-2026-98432, a remotely triggerable use-after-free in the IPv4/TCP handshake path. Bugs here potentially touch every Linux host that accepts inbound TCP.
  • In-kernel servers on well-known ports: ksmbd on 445, nfsd on 2049. Directly scannable, directly countable.
  • Kernel network protocol implementations behind radios: Bluetooth L2CAP and HIDP, NFC LLCP, wifi management frame parsers. Radio-adjacent rather than internet-facing, so scans do not see them, but peers can reach them.
  • Kernel code behind connection trackers and helpers: nf_conntrack_irc runs on routers and firewalls that pass IRC traffic. Its exposure is the exposure of the machines forwarding that traffic.
  • Local-only interfaces: sysfs attributes, DRM and accel ioctls, debugfs, and local privilege escalation bugs like Dirty Pipe (CVE-2022-0847) or the AF_UNIX garbage collector race I track as CVE-2026-80521. Scanners are blind to all of it, for reasons discussed near the end.

Only the first two classes are sizeable from service banners. For the rest you estimate proxies. Saying that out loud keeps the analysis grounded.

Finding the exposure in Netlas

Netlas indexes scan responses with a field-based query language over its responses collection. The baseline observations I use for triage, all taken in November 2026, in records:

protocol:http
  # 401,310,508 HTTP observations, one visible slice of TCP-facing services

port:445 protocol:smb
  # 608,395 SMB response records

port:2049
  # 22,533 records with something answering on the NFS port

port:22 protocol:ssh
  # 15,532,358 SSH response records

The SSH population is the workhorse for kernel work, because the banner names the operating system:

port:22 protocol:ssh ssh.banner:*Ubuntu*
  # 8,267,882 records with an Ubuntu banner

port:22 protocol:ssh ssh.banner:*Debian*
  # 2,605,516 records with a Debian banner

About 10.9 million records with an Ubuntu or Debian banner, before any deduplication. A real machine can appear in several of them, and the number says nothing about Linux hosts that do not expose an identifiable SSH service on port 22.

The baseline measurements in one place:

MeasurementQueryCountInterpretation
HTTPprotocol:http401.3MHTTP response records, a slice of TCP-facing services
SMBport:445 protocol:smb608KSMB candidate records, ksmbd not separable from Samba
SSHport:22 protocol:ssh15.5MSSH response records
Ubuntu SSHssh.banner:*Ubuntu*8.27MDistribution fingerprint
Debian SSHssh.banner:*Debian*2.61MDistribution fingerprint

Narrowing works the way you would hope. Country split for SMB:

port:445 protocol:smb geo.country:US
  # 135,644 records, about 22 percent of global SMB observations

Three things I learned the hard way, so you do not have to:

  • There is no useful free-text search. port:445 protocol:smb Samba returns zero. You must use field paths like ssh.banner, smb.smbv1_support, and smb.smb_version.version_string.
  • Port numbers lie. When I pulled a single sample record from port:2049 to check the NFS data, I got a Windows desktop machine serving TLS on that port, complete with a self-signed certificate reading DESKTOP-something. Port 2049 counts are a ceiling, not an NFS census. Always sample records before trusting a count.
  • Count endpoints are cheap, search endpoints are not. Count first, then pull samples only for the queries whose numbers you actually plan to publish.

Version hints from banners, and where they stop being reliable

The SSH banner gives you a version-era fingerprint, which is the most useful signal for kernel bugs with wide version windows, as long as you remember what it actually measures:

port:22 protocol:ssh ssh.banner:*Ubuntu* ssh.banner:*OpenSSH_7.6*
  # 226,209 Ubuntu records from the 18.04 generation

port:22 protocol:ssh ssh.banner:*Ubuntu* ssh.banner:*OpenSSH_8.2*
  # 666,461 Ubuntu records from the 20.04 generation

These banners provide a useful indication of the underlying distribution generation and potentially long-lived deployments. They cannot establish patch status, kernel version, or update frequency: Ubuntu backports security fixes while keeping the upstream OpenSSH version in the package banner, so an OpenSSH 7.6 banner identifies a software generation from 2018, not a machine that has or has not received its available security patches.

Now the limits on the SMB side. The version distribution looks like this:

port:445 protocol:smb smb.smb_version.version_string:"SMB 2.1"
  # 543,334 records

port:445 protocol:smb smb.smb_version.version_string:"SMB 3.1.1"
  # 124 records

If you read that as "89 percent of SMB observations are stuck on SMB 2.1," you are overreading it. What the scanner records is the dialect the negotiation selected during its probe, bounded by what the scanner itself offered. The number is a real property of the scan and a useful relative signal, but it is not a deployment survey.

The next letdown is native OS fingerprinting on SMB. Queries like smb.native_os:"*Unix*" and smb.native_os:"*Windows*" both return zero, because the native OS string only appears in a session setup the scanner never performs. An SMB negotiation record will hand you capabilities, dialect, GUID, and timestamps, but it will not tell you whether the thing on the other end is Samba in userspace or ksmbd in the kernel.

And even a perfect version string would not answer the question that matters, because distro kernels backport. Ubuntu's 6.8 kernel contains hundreds of fixes that upstream landed in 6.12 and later. A banner that says "6.8" tells you nothing about whether a specific 6.12 fix is present.

One more trap: Netlas has a vulnerability index, and you might expect it to answer directly. I ran the kernel CVEs from my own research shelf through it, and the contrast with a web-facing one is the lesson:

cve.name:"CVE-2026-31431"  # 32,803,859 records   (Copy Fail, kernel LPE)
cve.name:"CVE-2023-44487"  # 7,357 records        (HTTP/2, web-facing)

Most of the other kernel CVEs I tried, including Dirty Pipe, DirtyCOW, and the ksmbd pre-auth bug, returned exactly zero records. Those zeros exist because kernel bugs are simply not mapped into scanner CVE data, whose coverage skews toward web-facing services. And the one big kernel number looks like magic until you pull a sample record: it is an nginx host whose banner says "nginx/1.24.0 (Ubuntu)", the scanner matched the Ubuntu product, and attached the Ubuntu product CVE list, which currently includes Copy Fail. That is a product-level fingerprint, the banner naming the distro, not a verified kernel build. The same record carries half a dozen other Ubuntu CVEs it never checked for.

Note the syntax while we are here: the field is cve.name:"CVE-...", quoted, and a bare cve: returns zero even when data exists. The working rule for this index: a zero count is a coverage statement, never a safety statement, and a huge count is a product fingerprint, never a verified-vulnerable count. Sample a record before quoting either one.

Worked example one: a TCP stack bug with a version window

CVE-2026-98432 is the bug that made me build this workflow properly. It is a use-after-free in the IPv4/TCP handshake path, scored 9.8, introduced back in Linux 4.4 per the CVE announcement. The kernel builds an ip_options object for a request socket when a SYN carries IPv4 options, hands it to the child socket on handshake completion without copying it, and a concurrent CPU still inside the SYN-ACK path can read the object after the child is torn down. There are two relevant lifetime scenarios. One is a retransmitted connection request being processed while the child socket takes ownership of the object. The other is request socket migration, where cloned request sockets can share the same object and race with its destruction. Red Hat's writeup names both paths and is worth reading; MPTCP is not required. Ubuntu lists 6.8.0-147 as affected with the fix queued in 6.8.0-149. I have a proof of concept for the bug. I am not publishing the trigger details until the distribution fixes are out.

Sizing this with scan data, it helps to separate four different questions. Version exposure: is the running kernel in the affected range? Network reachability: does the host accept inbound IPv4 TCP at all? Trigger conditions: can the attacker deliver options-carrying requests and win the race? Exploitability: can the corruption be turned into more than a crash? Scan data speaks to the first two and is silent on the last two.

protocol:http                                          # 401,310,508 records
port:22 protocol:ssh ssh.banner:*Ubuntu*              # 8,267,882 records
ssh.banner:*Ubuntu* or *Debian*                       # ~10.9M records combined
ssh.banner:*Ubuntu* ssh.banner:*OpenSSH_7.6*          # 226,209 records

The read: any host running an affected kernel with IPv4 TCP enabled is potentially affected, and hosts accepting inbound IPv4 TCP connections have the most directly exposed attack surface. Netlas returned approximately 10.9 million Ubuntu- and Debian-banner SSH observations for that population. This is a measured candidate set, not an estimate of the entire Linux install base: it includes repeated observations, may represent multiple endpoints on the same machine, and excludes Linux systems that do not expose an identifiable SSH service on port 22, as well as every other distribution. Within the candidate set, the 18.04-generation counts identify long-lived deployments, which is where a wide-window bug does its worst damage over time. What this does not do is count exploitable endpoints, and it should never be quoted as one.

Worked example two: a kernel server bug, ksmbd

For in-kernel servers the analysis narrows to the service port. CVE-2022-47939 is the canonical case: a use-after-free in ksmbd, reachable before authentication. Per NVD, the affected upstream ranges are Linux 5.15 before 5.15.61, 5.16 through 5.18 before 5.18.18, and 5.19 before 5.19.2, so the fix landed in mid 2022, with the fix backported to the 5.15 and 5.18 stable series. Distribution kernels still need separate assessment, since backport timing varies by vendor.

Step one, the candidate set, every SMB speaker:

port:445 protocol:smb        # 608,395 records

Step two, narrow by geography when the question is regional, which is what a national CERT needs:

geo.country:US               # 135,644 records

Step three, state the conclusion: Netlas identifies SMB-speaking services, but the SMB negotiation response does not distinguish kernel-based ksmbd from userspace Samba, so 608,395 is an upper-bound candidate set, not a ksmbd exposure count. An upper bound is still useful: it gives a CERT a defensible denominator for an advisory and tells you whether the class is worth a same-day stable release or a normal cycle.

A separate observation, not a narrowing step. Cutting the same population by legacy dialect support:

port:445 protocol:smb smb.smbv1_support:true
  # 64,588 records still supporting SMBv1

This does not isolate ksmbd at all. ksmbd implements SMB 2.1 and later only, so this subset is interesting for general SMB hygiene, an aging tail of deployments that still speaks a dialect from 2006, but it cannot contain ksmbd endpoints. I am flagging it because my first draft of this analysis used it as a ksmbd proxy, which is exactly the kind of plausible-but-wrong inference banner data invites.

The local class: the limits of internet-wide scanning

Local privilege escalation bugs are the class scanners cannot see at all, and I keep a shelf of local kernel bugs with different impact profiles: Dirty Pipe (CVE-2022-0847) and DirtyCOW (CVE-2016-5195) as the classics with public, demonstrated privilege escalation; an AF_UNIX garbage collector race (CVE-2026-80521) that any unprivileged user can trigger, which the advisory discusses as a memory-safety race with instability and denial of service, escalation not established; and a netfilter xt_IDLETIMER use-before-initialization (CVE-2026-23274) affecting everything from v5.7 through v7.0-rc3. For this class the exposure question is: how many hosts could an attacker already run code on with a low-privilege account?

The SSH population is an indirect proxy, and its limits matter. An exposed SSH daemon does not tell you whether password authentication is on, whether only specific keys are permitted, whether accounts have interactive shells, whether the network path is restricted, or whether the running kernel is actually vulnerable to the specific LPE. It also does not make every local kernel bug an LPE: a local use-after-free is a local bug until someone demonstrates escalation.

So the statement I will defend is narrower: about 8.3 million Ubuntu-banner SSH records mark a large population of internet-facing Linux servers where, if an attacker obtains any low-privilege foothold by any means, and the host runs a kernel vulnerable to a public LPE, the path from foothold to root is one public exploit long. Both conditions are doing real work in that sentence, and neither is measurable from a banner. That is the limit of this tool for this bug class, and knowing where the tool stops is most of using it well.

Responsible use

Everything in this workflow is passive. Netlas gives you the scan responses its crawlers already collected; nobody sends a packet to a target because of your query. The rules I hold myself to:

  • Query aggregates, not victims. I publish counts and methods, never target lists. A query that isolates a vulnerable population is an attack map if it falls into the wrong hands, so the article says "ten million records" and not "here is how to enumerate them."
  • Respect scan freshness. These are snapshots with a scan date, not a live census. An observed service may be gone tomorrow, and a count from months ago is a historical claim, so date every number.
  • Route findings through the process. If exposure analysis turns up something urgent, the output goes to the distro security team or the CNA, not to a blog post first. The kernel CVE machinery exists precisely so nobody has to improvise disclosure under pressure.

The workflow, summarized

  1. Classify the bug's reachability: kernel network stack, in-kernel server, radio-adjacent, behind a helper, or local-only.
  2. Identify the component's actual prerequisites before sizing anything: what the bug needs on the wire, and what it needs the kernel to have or lack.
  3. For stack bugs, the candidate set is the Linux-identifiable TCP-facing population; size it with SSH banner counts and call it a candidate set.
  4. For server bugs, pick the scanner-visible signal: port first, then protocol tag, then banner fields.
  5. Count records, not hosts, until you have deduplicated, and label estimates as estimates.
  6. Narrow by geography or ASN to match whoever needs the number.
  7. Treat every version hint as an upper bound and a fingerprint of the software stack, never a verified kernel build, and say so in writing.
  8. Sanity-check zeros and suspiciously huge counts alike against known index coverage, and sample a record before quoting either.
  9. Publish the method and the aggregate, route specifics through coordinated disclosure.

It takes about a dozen queries, it is reproducible by anyone with a Netlas account, and it turns "how many machines does this touch" into a bounded, documented estimate. The strongest thing internet-wide scanning gives kernel research is not the numbers themselves but the map of what can be known, what can be estimated, and what cannot, and that map is most of the answer.

References

  1. Netlas API reference: docs.netlas.io/api-reference
  2. Netlas query language: docs.netlas.io/knowledge-base/query-language
  3. CVE-2026-98432 record: cve.org/CVERecord?id=CVE-2026-98432
  4. Red Hat on CVE-2026-98432: access.redhat.com/security/cve/CVE-2026-98432
  5. Ubuntu status for CVE-2026-98432: ubuntu.com/security/CVE-2026-98432
  6. CVE-2022-47939 on NVD, with the affected ranges quoted above: nvd.nist.gov/vuln/detail/CVE-2022-47939
  7. ksmbd kernel documentation, including the supported SMB dialects: docs.kernel.org/filesystems/smb/ksmbd.html
  8. My research notes on CVE-2026-80521 and CVE-2026-23274

Thanks to Arthur Kotylevskiy and the Netlas team for supporting the research. You can find the platform at netlas.io.