DIRTY STATIC / DISPATCH Tutorials05 NOV 2026 β€’ 18 MIN READ
An inspector with a clipboard standing before an open concrete server cabinet with a glowing yellow core inside, hazard stripes on the floor of a dark concrete server hall
TutorialsINTELLIGENCE FOR THE MACHINE AGE

Check Your Linux Servers After OpenAI's 948 Exploits: What You Can Check Now, and Why There Is No CVE List Yet

OpenAI reported 948 distinct Linux kernel flaws with working exploits and candidate patches, but published no CVE list, no affected versions, and no subsystems. This tutorial runs the checks that still matter today: record the running kernel, find pending updates and reboot state, read live patch status, count the local accounts an exploit would start from, and read the hardening values that shape access to kernel code.

Start reading ↓

The list everyone wants does not exist. OpenAI published its report, “A thousand fewer paths to root,” on November 4, 2026, and the report names no CVE identifiers, no affected kernel versions, and no subsystems. Our news report on the 948 exploits covers the counts, the costs, and the claims. This tutorial covers the machine in front of you, and it starts from an honest position: you cannot check a server against a list that nobody has published.

What you can check is everything around that missing list. An exploit in this class starts from an ordinary local account and ends at root. So the state of your kernel updates, your reboot queue, your live patch cover, your local accounts, and your kernel hardening values decides how much room such an exploit would have on your machines today. None of that needs the CVE list. All of it is work you would want done even if the list arrived tomorrow.

What You Will Build or Learn

You will end with a written record for one server, built from its own answers. The record states which kernel is running, which distribution release the machine runs, whether a kernel update waits to be installed, whether a reboot is already owed, whether a live patch service is covering the running kernel, which local accounts exist, and what six hardening values read on that machine.

You will also end with a clear reading of the OpenAI numbers. The pipeline produced 1,169 working local privilege escalation exploits, and variant analysis grouped those exploits into 948 distinct flaws, each with a candidate patch. Candidate is the word that matters. A candidate patch becomes a real fix only when kernel maintainers accept it and your distribution ships it. Ten days after the mid October scan, OpenAI says 61 of the flaws had already been patched upstream, 43 had patches in staging, and 299 were being reported and discussed in public. The rest were still moving through disclosure. That is why the practical answer today is patch cadence and local exposure, not a hunt for 948 names.

Before You Begin

Three limits shape this whole audit, and each one protects you from a wrong conclusion.

First, the missing list is real. The OpenAI report gives counts, stage costs, and patching status, and it gives no identifiers a tool could match against your kernel. Any scanner, blog post, or vendor pitch that claims to test your servers for the 948 by name is inventing the list it tests against. Treat such a claim as marketing and ask for its source data.

Second, a kernel version string is not a verdict. Distributions carry security fixes into older version numbers, a practice called backporting, so a kernel that looks old beside the newest upstream release may already carry a given fix. The opposite also holds. A new kernel package can sit installed on disk while the machine still runs the older kernel it booted last week. Judge by distribution advisories and by package state on the machine, never by comparing version numbers with upstream alone.

Third, local privilege escalation needs a local start. The attacker needs code running as some ordinary user on the box first: a person with an account, a service account for an app, or a workload inside a container. That fact sets the order of this tutorial. Kernel state first, then the accounts and workloads that could hand an attacker the starting position.

Step 1: Record the Running Kernel and the Distribution

Action: on the server, run these commands and save the output into a record file named for the host:

uname -r
cat /etc/os-release
{ uname -a; cat /etc/os-release; } > kernel-audit-$(hostname).txt

The first command prints the release of the kernel that is running right now, in a form such as 6.8.0-100-generic. The file /etc/os-release names the distribution and its release, which is the pair that decides which advisories and which package names apply to you. The third command writes both answers into one small file you can keep beside the rest of this audit.

Expected result: you hold three facts in writing, the hostname, the running kernel release, and the distribution release. Every later step is read against these three. If the running kernel release surprises you, that surprise is itself a finding, and Step 2 explains the most common cause.

A concrete desk with an old terminal showing abstract yellow lines, a printed checklist and a yellow pencil in a dark room The audit starts on paper: one record per server, built from what the machine reports about itself. Generated illustration in the Dirty Static house style.

Step 2: Find Pending Kernel Updates and Reboot State

Action, on Debian and Ubuntu: refresh the package lists, then ask what kernel packages wait to be installed. The refresh changes no packages. It only updates the lists your machine compares against.

sudo apt update
apt list --upgradable 2>/dev/null | grep -E '^linux-(image|generic|headers)'
dpkg -l 'linux-image-*' | grep '^ii'
ls -l /var/run/reboot-required
cat /var/run/reboot-required.pkgs

The first two commands show whether a newer kernel package is on offer. The third lists the kernel packages already installed on disk, and comparing its newest entry with the uname -r output from Step 1 tells you whether an installed kernel has never been booted. The last two commands read the reboot marker. The file /var/run/reboot-required exists only when an installed update has asked for a reboot, and its companion file names the packages that asked. If the ls command reports that the file does not exist, that error is the answer: no reboot is marked as owed.

Action, on the RHEL family:

dnf check-update
rpm -q kernel
sudo needs-restarting -r

The first command prints the updates on offer, and it exits with code 100 when updates exist, which is information and not a failure. The second lists installed kernel packages for the same comparison with uname -r. The third reports whether the running system needs a reboot to use updates already installed. The needs-restarting tool ships in the dnf-utils package, so a missing command means that package is absent, and the uname comparison above is your evidence until you install it.

Expected result: one of three readings per server. A kernel update is waiting, which sends you to Step 6. Or a kernel is installed and a reboot is owed, which also sends you to Step 6 and explains any odd Step 1 result. Or nothing waits and nothing is owed, which means your distribution has no newer kernel for you today, and the remaining steps decide your posture.

Step 3: Read Live Patch Status Where a Service Exists

Some servers receive fixes for serious kernel flaws applied to the running kernel, with no reboot, through a live patch service. The service covers only the flaws its maker judges safe to patch this way, and it never moves a machine onto a newer kernel. It is a bridge between reboots, and this step reads whether the bridge is actually in place.

Action, on Ubuntu:

pro status
sudo canonical-livepatch status

The first command shows whether the livepatch service is enabled. The second shows the running kernel it protects and its patch state. Read the patch state line at face value: it tells you whether patches are applied, whether none are needed yet, or whether the running kernel is not supported by the service at all. An unsupported kernel gets nothing from the service, whatever the subscription says, per the Ubuntu Pro documentation.

Action, on RHEL systems that use kpatch:

sudo kpatch list

Expected result: the tool lists the live patches loaded and installed for the running kernel, or it reports that the tool is absent, in which case record that no live patch service runs on this server. On any system without a live patch service, record the same plain answer and rely on Steps 2 and 6. A blank here is not a failure of the audit. It is the fact that reboots are your only route to kernel fixes on that box.

Step 4: Count the Local Accounts an Exploit Would Start From

Action: list the ordinary accounts on the server. On most systems, accounts for people start at user ID 1000, and the account named nobody sits far above that range, so this filter shows the human and service accounts that matter:

awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6, $7}' /etc/passwd
getent group sudo
getent group wheel
who

Read the output as a roll call. The first command prints each account name, its home folder, and its login shell. The next two commands name the members of the groups that can gain root by design, sudo on Debian and Ubuntu and wheel on the RHEL family. An exploit that reaches root from an ordinary account makes those group lists more important, not less, because they show who already holds a managed route upward. The last command shows who is signed in now.

A concrete vault door with rows of metal keys on hooks, a few of them painted caution yellow Every local account is a key on the wall. The audit counts them and checks which ones you recognise. Generated illustration in the Dirty Static house style.

Action: if the server runs containers, list them and check whether any run in privileged mode:

docker ps
docker ps -q | xargs -r docker inspect --format '{{.Name}} privileged={{.HostConfig.Privileged}}'

Use the podman equivalents on systems that run Podman. If neither tool exists, record that and move on. Containers share the kernel of the host, so patching a container image does nothing for a kernel flaw. The host is the target, and a container running with privileged set to true holds broad access to that host, so each such container belongs on your list of starting positions beside the human accounts.

Expected result: a list of accounts and workloads you recognise, each one owned by a person or a service you can name. Any name you cannot place is the most valuable finding in this step. Remove or disable an account only through your normal change process, with the service owner in the loop, because a service account that looks idle may still run a nightly job.

Step 5: Read the Hardening Values That Shape Kernel Access

Kernel settings, read and changed with the sysctl tool, decide how much of the kernel an ordinary user can touch or see. This step only reads six values. It changes none of them, and the notes below explain what each reading means so you can record it with understanding rather than as a bare number.

Action: run:

sysctl kernel.kptr_restrict kernel.dmesg_restrict kernel.perf_event_paranoid kernel.unprivileged_bpf_disabled
sysctl user.max_user_namespaces
sysctl kernel.unprivileged_userns_clone

The third command may report that the key does not exist. That key ships only on some distributions, chiefly the Debian family, so an error there means the control is absent on this kernel. Record absent as absent. Do not record it as zero, because the two readings mean different things.

How to read the values, against the kernel documentation:

  • kernel.kptr_restrict controls whether kernel memory addresses are hidden when printed. At 1, addresses are replaced with zeros for users who lack the CAP_SYSLOG capability, with conditions the documentation spells out. At 2, they are zeroed for everyone. At 0, addresses are hashed before printing. Higher is tighter, and this value bears on the information leak side of the OpenAI results.
  • kernel.dmesg_restrict at 1 means only users with CAP_SYSLOG can read the kernel log through the dmesg tool. At 0, any local user can read it.
  • kernel.perf_event_paranoid controls the perf measurement tool. Higher numbers restrict it more, and distributions ship different defaults, including a value of 4 on Ubuntu that upstream does not define. Record the number and compare it with your own fleet rather than with a universal table, because no universal default exists.
  • kernel.unprivileged_bpf_disabled at 1 or 2 means ordinary users cannot make unprivileged calls into eBPF, the in kernel virtual machine that a long line of past escalation flaws has abused. The kernel documentation adds a warning worth knowing before you ever set this value yourself: once set to 1, the setting cannot be cleared until the machine reboots.
  • user.max_user_namespaces caps how many user namespaces can be created. A value of 0 closes creation entirely. A large value leaves creation open, subject to other controls.
  • kernel.unprivileged_userns_clone, where it exists, at 0 means only privileged users can create user namespaces. User namespaces are a sandbox tool that many container setups and browsers rely on, and they are also a common entry point in past escalation exploits, because a namespace grants its creator raised privileges inside it over kernel objects the host can see.

Expected result: six readings, or five readings plus one recorded absence, per server. This tutorial does not tell you to change any of them on a production machine today. Changing namespace or eBPF settings can break rootless containers, sandboxes, and tools that depend on them, so each change belongs in a test on a spare host first, one change at a time, with a way back.

Step 6: Install the Kernel Your Distribution Offers, Then Reboot

Action, on Debian and Ubuntu:

sudo apt update
sudo apt full-upgrade
sudo reboot

Action, on the RHEL family:

sudo dnf update
sudo reboot

Where your policy allows security updates only, add the security flag to the dnf command in place of a full update, and accept that other packages then wait for their own window. After the machine returns, repeat Step 1 and Step 2 on it.

Expected result: uname -r now prints the newer kernel release that Step 2 showed as installed, the list of upgradable kernel packages is empty, and the reboot marker is gone. If uname -r still prints the old release, the machine booted its previous kernel, and the Troubleshooting table below covers that reading.

Verification

The audit worked when your record places each server in exactly one row of this table, using evidence from the machine itself.

Evidence from your recordReading
Kernel update waiting in Step 2, or reboot marker presentExposed by delay. The fix exists and the machine is not running it. Step 6 is the whole remedy, inside a window.
Installed kernel newer than the running kernelSame reading as above, with the cause named. The update landed and the reboot never happened.
Live patch service enabled, kernel supported, patch state applied or none neededCovered between reboots for the flaws the service selects. Normal kernel updates still apply at their normal cadence.
Live patch answer absent or kernel unsupported, and no update waitingCurrent through the package route only. Your posture is your reboot cadence, and nothing else stands between a flaw and its fix.
An account or a privileged container that nobody can nameA starting position you did not know you offered. Resolve it through your change process before you worry about kernel values.
Namespace creation open and unprivileged eBPF enabled on a server that runs untrusted local workloadsA wider local surface than the task needs. A candidate for tested tightening later, never a same day edit on a production box.
No update waiting, accounts all named, live patch state read and recordedAs current as today allows. No check can say more while the 948 carry no identifiers, and anyone who claims more is guessing.

Troubleshooting

ProblemLikely causeFix
uname -r still shows the old kernel after Step 6The machine rebooted into its previous kernel, or the new kernel package installed without becoming the boot defaultCompare the installed list from Step 2 with the running release, check the boot loader menu selection, reboot once more, and read uname -r again before judging.
The running kernel number looks older than the newest upstream kernel, yet the distribution lists the flaw class as fixedBackporting. The distribution carried the fix into its own version numberTrust the distribution advisory and the package changelog for your exact release over any upstream number comparison.
needs-restarting is not foundThe dnf-utils package is not installed on RHEL family systemsInstall dnf-utils through your normal process, or rest the reboot judgement on the installed versus running comparison in Step 2.
canonical-livepatch status says the kernel is not supportedThe running kernel sits outside the list the Livepatch service coversThe service applies nothing to that kernel. Move the machine onto a supported kernel through Step 6 and read the status again.
sysctl reports that kernel.unprivileged_userns_clone does not existThe key ships only on some distributionsRecord the control as absent on this kernel. Judge namespace exposure by the user.max_user_namespaces reading instead.
dnf check-update finishes with an error style message and code 100Code 100 is the documented signal that updates existRead the printed list. It is a finding, not a failure.
No kernel update is on offer and the news sounds urgentNo newer kernel has been published for your release yet, which is the normal state while the 948 move through disclosureHold your normal cadence, keep the record from this audit, and recheck after your distribution publishes its next kernel. Do not install kernels from outside your distribution channels as a shortcut.
A hardening change broke a container or a sandbox in testingThe workload depends on user namespaces or on unprivileged eBPFRevert that single change on the test host, record the dependency, and scope any later change to servers that do not run that workload.

Next Steps

Turn this audit into a rhythm rather than an event. Subscribe to the security notices of the distribution each server runs, Ubuntu Security Notices, the Debian security tracker, or Red Hat security data, and let those feeds drive your kernel cadence instead of headlines. Where your policy allows it, switch on automatic installation of security updates, through the unattended-upgrades package on the Debian family or dnf-automatic on the RHEL family, while keeping reboots as planned events you control.

Then watch for the one thing that would change this tutorial: identifiers. When reports from the OpenAI run reach maintainers and the public record, CVE assignments and distribution advisories will give defenders a list at last. Recheck your Step 1 records on the day your distribution publishes kernel fixes tied to those assignments, and expect that day to arrive in stages over weeks, not as a single drop. Until then, the servers that come out of this audit with current kernels, short account lists, and honest records are as defended as the public facts allow.

Commands and value meanings checked against the Linux kernel sysctl documentation, the Ubuntu Pro Livepatch documentation, and the OpenAI research post, November 2026. This audit was verified against those documents and was not run against a production server in this run, so confirm each reading on your own hardware as the Verification table directs.

Sources

β– 

END OF TRANSMISSION

Stay curious. Question everything.

CONTINUE THE DESCENT

MORE FROM DIRTY STATIC β†˜