CyberBytes Daily

Trending cyberattacks, explained simply.

critical vulnerability

How a 15-year-old logic error in the Linux kernel lets any user claim root, escape containers, and take over a phone with one link

A bug introduced into the Linux kernel in 2011 sat undetected in every mainstream Linux distribution for 15 years. Not because it was hidden. Not because it was obscure. Because the kernel's own security auditing tool, the one specifically designed to catch this class of error, was checking the wrong thing. It verified that a lock was held. It never checked whose lock it was.

That single oversight left a dangling pointer on a sleeping thread's kernel stack, and a dangling pointer on a kernel stack is enough to take full control of a machine. The vulnerability, named GhostLock and tracked as CVE-2026-43499, requires no special permissions. Any logged-in user, any developer with SSH access, any process running inside a Docker container, can trigger it. On July 8, 2026, the researchers who found it published a working exploit that succeeds 97% of the time.

The detail that should concern every organization running Linux infrastructure: this exploit also breaks out of containers. A single compromised container on a Kubernetes node can use GhostLock to own the underlying host and pivot to every other workload sharing that machine. And when chained with a Firefox browser bug (CVE-2026-10702), the full attack requires nothing more than a victim clicking a link.

Narrative · 7 min read

The Context

Linux is the operating system running the majority of the world's servers, cloud infrastructure, Android phones, and container platforms. When security researchers talk about a "kernel vulnerability," they mean a flaw in the core of that operating system—the layer that controls memory, processes, and hardware access. A bug at that level sits below every other security control: firewalls, antivirus software, and container isolation all depend on the kernel being trustworthy. GhostLock is a flaw in that foundation.

The bug lives in a subsystem called rtmutex, which manages how the kernel handles competing threads that need access to shared resources. It has been present in every major Linux distribution since 2011. It was discovered not by a human auditor but by VEGA, an AI-driven code-scanning tool built by Nebula Security, a Y Combinator-backed startup. Nebula reported it to the Linux kernel security team on April 18, 2026. The fix landed in Linux 7.1. The public exploit followed on July 8, 2026.

The Attack, Phase by Phase

Phase 1: The Hidden Bug (2011 to April 2026)

The error is a logic mistake in a function called remove_waiter(), inside the kernel's locking subsystem. When multiple threads compete for a shared resource, the kernel tracks which thread is waiting and why. On a specific, rarely-tested path called Requeue-PI, one thread performs cleanup on behalf of a different, sleeping thread. The function was never updated to account for this: it cleans up the running thread's state instead of the sleeping thread's, leaving a pointer into memory that has already been freed.

The kernel's own locking auditor, lockdep, was supposed to catch this class of error. It checked that the right kind of lock was held. It never checked whether the lock belonged to the right thread. The bug was invisible to the tool designed to find it.

INSIDE THE LINUX KERNEL, 2011 TO 2026🔧1rtmutex rework lands (2011)remove_waiter() assumes caller owns waiter🔍2Lockdep audits lockingChecks lock is held, not whose lock it is⚠️3Logic error goes undetectedWrong thread's state cleared on Requeue-PI💀4Dangling pointer left on stackFreed memory still referenced by sleeping threadThe bug passed every automated check for 15 years because the auditor asked the wrong question.

Phase 2: Triggering the Use-After-Free

An attacker with any local user account—no special permissions required—constructs a specific sequence using three threads and three shared memory words. This forces the kernel down the Requeue-PI path into a rollback condition. The cleanup function runs in the wrong context, clears the wrong thread's state, and leaves a dangling pointer on the sleeping thread's kernel stack. That freed memory region is now available for the attacker to reclaim and fill with their own data.

ATTACKER WITH ANY LOCAL USER ACCOUNT🧵1Three threads constructedForces Requeue-PI rollback path2Wrong cleanup runsremove_waiter() clears wrong thread's state🎯3Dangling pointer createdFreed stack frame still referencedNo special privileges, capabilities, or user namespaces required.

Phase 3: Stack Reclaim, Pointer Write, and Function Table Hijack

Using standard Linux system calls, the attacker reclaims the freed kernel stack frame and writes a forged data structure into it. The kernel's internal bookkeeping mechanism then performs a write operation using the attacker's forged data, overwriting a kernel function table entry—specifically, the entry that tells the kernel which code to run when it receives a certain type of network packet.

The attacker sends a loopback packet to themselves. The kernel looks up the function table, finds the attacker's pointer, and jumps to attacker-controlled code. A short instruction sequence flips a single permission bit, completing the privilege escalation entirely in userspace.

To aim this precisely, the attacker needs to know where the kernel is loaded in memory. KASLR is supposed to prevent this by randomizing the kernel's location. GhostLock defeats KASLR via a timing side-channel: by measuring how long certain memory prefetch instructions take, the attacker infers the kernel's base address with near-100% reliability, because Linux's kernel image randomization has only about 9 bits of entropy—roughly 512 possible locations.

KERNEL MEMORY MANIPULATION♻️1Freed stack frame reclaimedForged waiter struct written into freed memory✍️2Constrained pointer writerb-tree erase overwrites function table entry📡3Loopback UDP packet sentKernel jumps to attacker-controlled code👑4Root achievedSingle bit flip via DirtyMode techniqueCONTROL FLOW HIJACKEDKASLR bypassed via prefetch timing side-channel: only ~512 possible kernel locations.

Phase 4: IonStack Chain, Container Escape, and Public PoC

GhostLock on its own requires local access. Nebula extended it into a fully remote attack by chaining it with CVE-2026-10702, a flaw in IonMonkey, the just-in-time compiler inside Firefox. A victim visits a malicious URL. The Firefox bug executes attacker code inside the browser's renderer process. GhostLock then carries the attacker from that sandboxed process to full kernel root. Nebula demonstrated this end-to-end on a fully updated Android 17 device running Firefox 151, with the exploit changing the device wallpaper as visible proof of root.

The same kernel component powers container runtimes. GhostLock breaks out of Docker, Podman, and LXC containers onto the host—meaning a single compromised container on a shared Kubernetes node can own the host and pivot to every other workload on that machine.

On July 8, 2026, Nebula published the full writeup and open-source exploit code on GitHub. Publication was required by Google's kernelCTF bug bounty program as a condition of the $92,337 award. The exploit is now public. Patches are not yet universally deployed.

FULL IONSTACK CHAIN🔗1Victim clicks malicious URLFirefox IonMonkey JIT bug triggers🌐2Browser sandbox escapedRemote code execution in renderer💀3GhostLock escalates to rootCVE-2026-43499 runs from sandboxed process🐳4Container escape to hostDocker, Podman, LXC all affected📱Android 17 deviceFull root from one URL click☁️Kubernetes nodeAll workloads on host compromised📢Public PoC live97% reliable, open-source on GitHubThe kernelCTF bounty required publishing the exploit. Transparency and attacker access arrived simultaneously.

What Made This Possible

  1. The auditor checked the wrong property. Lockdep verified that a lock was held. It did not verify that the lock belonged to the thread performing the cleanup. A security tool that asks a slightly wrong question provides false confidence for 15 years.

  2. "Local only" is not a meaningful boundary anymore. GhostLock was classified as a local privilege escalation. That classification assumes a clear separation between remote and local access. Browser exploits routinely collapse that boundary: a single malicious URL is now a local access primitive.

  3. Container isolation depends entirely on kernel integrity. The security model of containers assumes the kernel is trustworthy. GhostLock sits below that assumption. Any multi-tenant environment where workloads share a kernel—every Kubernetes cluster and most cloud infrastructure—inherits the full blast radius of a kernel privilege escalation.

What Should Have Stopped This

  • Patch the kernel. The fix is in Linux 7.1 (CVE-2026-43499). Distribution patches for Ubuntu, Debian, Red Hat, and others are available or in progress. This is the only complete fix.
  • Enable RANDOMIZE_KSTACK_OFFSET. This kernel compile option randomizes the stack offset per system call, making it harder to predict where the freed stack frame lands. It raises exploitation difficulty without preventing the bug.
  • Enable STATIC_USERMODE_HELPER. This restricts the kernel's ability to execute userspace programs, limiting the final step of the DirtyMode technique.
  • Restrict container privileges. Running containers with --no-new-privileges and dropping unnecessary capabilities limits what a compromised container process can attempt.
  • Update Firefox. The browser component (CVE-2026-10702) is patched in Firefox 151.0.3. Without this fix, the remote attack path remains open even on patched kernels.

The Takeaway

GhostLock is not primarily a story about a missing patch. It is a story about what happens when a security tool validates the right category of property but the wrong specific instance of it. Lockdep confirmed that a lock existed. It never asked whether it was the right thread's lock. That distinction—invisible in normal operation—is the entire attack surface.

The IonStack chain makes the systemic lesson concrete: the conventional risk model separating "remote" from "local" vulnerabilities is a classification that attackers do not respect. A "local-only" kernel bug chained with a browser bug is a remote root exploit. Risk assessments that treat these as separate categories will consistently underestimate real exposure.

Pattern to remember: A security validator that checks the right category but the wrong instance provides false confidence that is worse than no check at all, because it closes the investigation before the real question is asked.

What changed: The kernel's own locking auditor now requires explicit per-task ownership verification, not just lock-held confirmation, closing a class of proxy-path identity errors that automated tooling could not previously distinguish from correct behavior.

Technical Deep Dive · 3 min

The Technical Mechanism

GhostLock is a stack use-after-free (UAF) in kernel/locking/rtmutex.c, specifically in remove_waiter(). The root cause is a task-identity mismatch on the FUTEX_CMP_REQUEUE_PI path.

On the normal slow path, remove_waiter() clears current->pi_blocked_on because the running thread owns the rt_mutex_waiter object on its own stack. On the proxy path, rt_mutex_start_proxy_lock() enqueues an rt_mutex_waiter on behalf of a sleeping thread. When a -EDEADLK rollback occurs, remove_waiter() still clears current->pi_blocked_on, but current is now the requeuing thread, not the sleeping waiter. The sleeping thread's pi_blocked_on is left pointing into its own freed kernel stack frame.

Triggering the -EDEADLK rollback requires a PI dependency cycle constructed with three futex words and three threads, all achievable with unprivileged futex(2) and clone(2) syscalls. The bug evades lockdep because lockdep verifies only that pi_lock is held, not that it is the correct task's pi_lock.

Six-stage exploit chain:

  1. Dangling waiter creation. Trigger the Requeue-PI rollback to leave a freed rt_mutex_waiter referenced by the sleeping thread's pi_blocked_on.
  2. Stack reclaim. Use PR_SET_MM_MAP with a memfd-backed auxv straddling a page boundary, combined with a racing fallocate(FALLOCATE_FL_PUNCH_HOLE) call, to reclaim the freed kernel stack frame and write a forged rt_mutex_waiter into it.
  3. Constrained pointer write. The rtmutex red-black tree erase path (rt_mutex_dequeue) writes a child node into the root slot when erasing a single-child root. With the forged waiter, this yields a constrained but usable kernel pointer write.
  4. Function table hijack. The pointer write overwrites inet6_protos[IPPROTO_UDP] with a pointer into the CPU entry area (CEA). A fake inet6_protocol struct, JOP pivot slots, and a ROP stack are staged at a known direct-map address in the CEA.
  5. Control flow hijack. Sending a loopback IPv6 UDP packet triggers the overwritten protocol handler, pivoting execution into the attacker's ROP chain.
  6. DirtyMode LPE. A single ROP write flips the mode bits of core_pattern's sysctl (coredump_sysctls[1].mode), after which full local privilege escalation completes in userspace.

KASLR bypass: A prefetch timing side-channel exploits Linux's approximately 9 bits of kernel image entropy (roughly 512 possible base addresses), recovering the kernel base with near-100% reliability. Nebula assesses the exploit is viable on single-core CPUs due to the wide race window.

IonStack chain: CVE-2026-10702 is an instruction-modeling flaw in IonMonkey, Firefox's JIT compiler. A malicious page triggers JIT miscompilation, achieving remote code execution inside the Firefox renderer process and escaping the browser sandbox. GhostLock then escalates from the sandboxed renderer to kernel root. Demonstrated on Android 17 arm64 running Firefox 151.

GHOSTLOCK TECHNICAL EXPLOIT FLOW🧵1Requeue-PI rollback triggeredremove_waiter() clears wrong task's pi_blocked_on♻️2Stack frame reclaimedPR_SET_MM_MAP + fallocate(PUNCH_HOLE) race✍️3rb-tree erase pointer writeOverwrites inet6_protos[IPPROTO_UDP]📡4Loopback UDP triggers CFHFake inet6_protocol handler executes ROP👑5DirtyMode LPE completescore_pattern mode bits flipped in userspaceKASLR defeated via prefetch timing side-channel before step 3.

CVE and Advisories

  • CVE-2026-43499 — GhostLock: Linux kernel rtmutex stack use-after-free. CVSS 7.8 (High). Fixed in Linux 7.1 via commit 3bfdc63936dd.
  • CVE-2026-10702 — IonMonkey JIT instruction-modeling flaw in Firefox. Fixed in Firefox 151.0.3.
  • CVE-2026-53166 — Null-pointer dereference introduced by the initial GhostLock patch. Required a follow-up fix; some early-patched builds may lack the final correction.

No CISA Known Exploited Vulnerabilities (KEV) catalog entry for CVE-2026-43499 as of July 8, 2026. No in-the-wild exploitation confirmed at time of disclosure.

MITRE ATT&CK Mapping

Technique IDATT&CK nameHow it appeared
T1068Exploitation for Privilege EscalationGhostLock exploits CVE-2026-43499 to escalate from any local user to kernel root via stack use-after-free in rtmutex.
T1611Escape to HostThe exploit breaks out of Docker, Podman, and LXC containers onto the underlying host, defeating container isolation.
T1189Drive-by CompromiseIonStack chain: victim visits a malicious URL, triggering CVE-2026-10702 in Firefox IonMonkey to achieve initial remote code execution.
T1055Process InjectionROP chain execution pivots control flow through the overwritten inet6_protos function table entry.
T1082System Information DiscoveryPrefetch timing side-channel used to defeat KASLR and recover kernel base address before exploitation.

Indicators of Compromise

GhostLock leaves minimal forensic artifacts. The exploit operates entirely through standard, unprivileged syscalls (futex, clone, PR_SET_MM_MAP, fallocate, loopback UDP). No unusual binaries, no kernel modules, no network connections to external infrastructure are required.

Detection is difficult at the syscall level because the individual calls are legitimate. Behavioral detection should focus on:

  • Unusual futex(FUTEX_CMP_REQUEUE_PI) call patterns from non-privileged processes
  • PR_SET_MM_MAP invocations combined with memfd_create and fallocate(PUNCH_HOLE) in rapid succession
  • Unexpected privilege transitions (UID 0 processes spawned from browser renderer or container processes)
  • Modifications to /proc/sys/kernel/core_pattern permissions or content
  • Loopback IPv6 UDP traffic from non-network-service processes

No public YARA rules or Sigma detections specific to GhostLock were available at time of disclosure.

Attribution

GhostLock was discovered by VEGA, Nebula Security's AI-driven automated code-scanning agent. Nebula Security is a Y Combinator-backed security startup. Both CVE-2026-43499 and CVE-2026-10702 were responsibly disclosed to the respective vendors before the public demonstration. No threat actor, nation-state group, or criminal organization has been associated with the discovery or exploitation of this vulnerability. No in-the-wild exploitation has been confirmed as of July 8, 2026.


Primary Sources