Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessGain local access with mount privileges (user namespace)
-
DeliveryClone detached mount tree covering target file
-
ExploitRace unlink/rmdir against a reference-walk lookup
-
ExecutionRefwalk misses detached mounts and accepts unhashed dentry
-
ImpactRead revealed underlying file contents
Vulnerability Assessment
| Exploitation Conditions | Requires local code execution plus the ability to create and manipulate mounts - open_tree(OPEN_TREE_CLONE) and move_mount - which typically needs CAP_SYS_ADMIN, obtainable by unprivileged users via user namespaces on distros that enable them. The attacker must set up a locked/covered mountpoint over data they want to read and then win a very narrow timing race between a refwalk taking a reference on the hashed dentry and an unlink()/rmdir()/rename() that detaches the mounts and removes the name. Limiting factors: the race window is extremely small (the reproducer required thousands of unlinks and artificial timing widening to hit it), exploitation yields only disclosure of an overmounted entry rather than code execution, and it is meaningful only where a sensitive file is hidden behind a mount the attacker can trigger detachment of. |
| Impact | Signals point consistently to a low-to-moderate real-world priority despite the vendor CVSS of 8.8. The CVSS vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H describes local access with low privileges, but two of its claims are questionable against the description: the flaw is an information-disclosure race (the Tags and the text both say reads of a covered file are the 'hit'), so I:H and A:H appear overstated - there is no integrity or availability impact in the described mechanism. The description also explicitly calls this 'a very narrow window,' which argues for high attack complexity rather than the AC:L the vendor assigned; the supplied reproducer needed ~15000 unlinks and timing widening to score hits, confirming the race is hard to win reliably. EPSS is low at 0.21% (11th percentile) and the CVE is NOT in CISA KEV, so there is no evidence of active or widespread exploitation. The vuln.today decision label is 'this_week,' indicating patch-cycle urgency rather than emergency. Exploitation status: no public exploit identified at time of analysis as confirmed working code, though a public PoC reproducer is embedded in the fixing commit (see exploit scenario). Net: this is a legitimate local confidentiality bug worth patching on a normal stable-kernel cadence, not a high-CVSS emergency - the headline 8.8 is inflated by scope-change and I/A impact assignments that the described mechanism does not support. |
| Exploit ScenarioDerived | A local user creates a detached clone of a mount (open_tree(OPEN_TREE_CLONE) + move_mount) so a sensitive file is covered by a bind mount, then repeatedly opens that path via a reference walk while another thread unlinks the underlying covered name. If the refwalk takes its dentry reference in the narrow window after the reference is acquired but before the detached mounts are traversed, it reveals and reads the underlying (supposedly hidden) file content instead of the mounted overlay. A reproducer is included in the fixing commit; it is not verified as a standalone weaponized exploit, and the window is very narrow. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 24, 2026
Race in the Linux kernel's VFS path-resolution (refwalk) code lets a local attacker who can create and move mounts read the contents of a file that is supposed to be hidden behind an overmount, instead of receiving ENOENT or the covering file. The flaw sits in step_into()/step_into_slowpath(): a refwalk takes a reference on the hashed dentry and accepts it without revalidating, so an unlink()/rmdir()/rename() that detaches the mounts and removes the name can leave the walker looking at the underlying entry. Winning the race requires CAP_SYS_ADMIN-style mount manipulation (open_tree(OPEN_TREE_CLONE), move_mount), typically obtained through unprivileged user namespaces, plus a very narrow timing window - the supplied reproducer needed thousands of unlinks and artificial delay widening to trigger it reliably. Impact is confidentiality-only information disclosure (our assessed vector AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N), considerably narrower than the vendor's 8.8 score; a public reproducer accompanies the fix commits, EPSS is 0.21% (11th percentile), and there is no KEV listing indicating active exploitation.
RemediationAI
Vendor-released patch: apply the kernel stable updates that carry the fix - 6.18.57, 6.12.113, 7.2.11 or 7.3 - or cherry-pick the corresponding upstream commits (8189ab688f5a, 5f97df8ca7fa, e2b10181d913, b43ff2deef48) listed under https://git.kernel.org/stable/c/, and follow the NVD entry https://nvd.nist.gov/vuln/detail/CVE-2026-98980 for downstream distribution advisories. Because exploitation requires the ability to create and move mounts (open_tree(OPEN_TREE_CLONE), move_mount) on data the attacker wants to expose, the practical compensating control is to remove that capability from untrusted users by disabling unprivileged user namespaces - set user.max_user_namespaces=0, or kernel.unprivileged_userns_clone=0 on distributions that expose that sysctl - which denies the CAP_SYS_ADMIN obtainable in a new namespace; the trade-off is that it breaks unprivileged container runtimes, rootless Podman/Docker, browser and application sandboxes, and some build tooling, so scope it to systems that do not rely on those workloads. Restricting the set of users permitted to perform mount operations (dropping CAP_SYS_ADMIN from service accounts, keeping mount namespaces isolated from untrusted processes) reduces the attack surface with the same functional costs, and neither workaround corrects the race itself - updating the kernel is the only complete fix.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in euvd
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
This is a VFS lookup-consistency bug rather than a memory-safety issue; no CWE is assigned in the available source data, but the class is a time-of-check/time-of-use race producing information disclosure. The kernel has two path-walk modes: rcu-walk validates the dentry before accepting it (step_into() rechecks d_seq and __follow_mount_rcu() rechecks mount_lock, so an unlink in between forces a retry), whereas ref-walk's lookup_fast() simply takes a reference on the hashed dentry and accepts it, so an unlink occurring after that reference is not observed. For an ordinary file this is harmless - the file was open before it was unlinked. For a mountpoint (especially a locked one) it is not: unlink() marks the dentry DCACHE_CANT_MOUNT via dont_mount(), detaches all mounts, then removes the name. A refwalk that has not yet traversed the mounts therefore reveals the underlying entry that the mount was meant to cover. The fix adds a check in step_into_slowpath(): a dentry carrying DCACHE_CANT_MOUNT that is unhashed by the time its mounts were examined is treated as a name unlinked beneath the refwalk. The patch notes careful distinctions - plain d_unlinked() is acceptable, ___d_drop() leaves d_hash.pprev set so only __d_drop() or a rename-over unhashes it, and the IS_ROOT splice of a disconnected alias does not carry the flag; ".." and LOOKUP_DOWN may legitimately land on an unhashed directory, and dentries dropped by a filesystem itself (d_invalidate(), d_drop()) lack the flag and behave as before. The included reproducer (unlink_covered) builds a tmpfs A with file f1, takes an open_tree(OPEN_TREE_CLONE) copy A', binds MARK_A over A'/f1, and has walkers use openat2(RESOLVE_CACHED) through an O_PATH fd while a driver unlinks A/f1; reading the secret f1 content rather than MARK_A or ENOENT is the hit condition.
Know when the next one hits your stack
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
Local mount setup needs privileges typically via a user namespace (PR:L); success depends on a very narrow unlink/refwalk timing race (AC:H); impact is disclosure only, so C:H with I:N and A:N.
Primary rating from Vendor (Linux).
CVSS VectorVendor: Linux
Lifecycle Timeline
4DescriptionCVE.org
In the Linux kernel, the following vulnerability has been resolved:
namei: don't reveal overmounted entries in refwalk
In rcuwalk the dentry is validated before it is accepted. step_into() step_into() rechecks d_seq and __follow_mount_rcu() rechecks mount_lock. An entry that gets unlinked in between causes the lookup to retry and miss.
A refwalk doesn't do this. lookup_fast() takes a reference on the hashed dentry and simply accepts it. So an unlink that happens after the reference was taken isn't seen by refwalk. That's fine for a simple file. We just happened to open it before it was unlinked, no problem.
For a mountpoint and specifically a locked mountpoint it very much isn't. The unlink detaches all mounts and then removes the name. Any refwalk that hasn't traversed the mounts yet simply reveals the underlying entry. It's a very narrow window but it can be hit:
reads of a covered file in 60 s, 3 walkers, ~15000 unlinks no widening 27 that step + 200 us 3741
See the appended patch for a more reliable reproducer.
So check the entry after step_into(). unlink(), rmdir() and rename() mark the dentry with dont_mount() before they detach the mounts and remove the dentry.
So a dentry that is marked with DCACHE_CANT_MOUNT and is unhashed by the time its mounts were looked at is a name that was unlinked under the refwalk. DCACHE_CANT_MOUNT is read after the mounts were looked up and it is set before they are detached by detach_mounts(). A refwalk that missed the mounts will see DCACHE_CANT_MOUNT.
Plain d_unlinked() is fine. A rename takes the dentry off its hash chain but ___d_drop() leaves d_hash.pprev set. So only __d_drop() and a rename over the dentry unhash it. The only move that flips IS_ROOT splices in a disconnected alias. That doesn't have DCACHE_CANT_MOUNT set.
Add the to step_into_slowpath(). ".." and LOOKUP_DOWN may legitimately land on an unhashed directory. A refwalk that crossed onto a mount has path.mnt different from nd->path.mnt. A dentry that a filesystem dropped on its own (d_invalidate(), d_drop()) doesn't have the flag set and is treated as before.
// SPDX-License-Identifier: GPL-2.0 /*
- unlink_covered: unlink a file that is a mountpoint in a detached copy of
- its mount, against walkers that open it through that copy.
*
- A is a tmpfs with the file f1 (content SECRET_F) and the plain file
- MARK_A. A' is an open_tree(OPEN_TREE_CLONE) copy of A with MARK_A bound
- on A'/f1, held through an O_PATH fd on its root once the tree fd is
- closed. Walkers open f1 through that fd while the driver unlinks A/f1,
- where nothing is mounted on it. A walker may read MARK_A or get ENOENT.
- A read of SECRET_F is a hit: the name was found after its mount was
- gone. The lockless walks use openat2(RESOLVE_CACHED).
*
- usage: unlink_covered [-t seconds] [-w walkers]
*/ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <errno.h> #include <fcntl.h> #include <pthread.h> #include <stdatomic.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/mount.h> #include <sys/stat.h> #include <sys/syscall.h> #include <linux/openat2.h>
#ifndef __NR_open_tree #define __NR_open_tree 428 #endif #ifndef __NR_move_mount #define __NR_move_mount 429 #endif #ifndef __NR_openat2 #define __NR_openat2 437 #endif #ifndef OPEN_TREE_CLONE #define OPEN_TREE_CLONE 1 #endif #ifndef OPEN_TREE_CLOEXEC #define OPEN_TREE_CLOEXEC O_CLOEXEC #endif #ifndef MOVE_MOUNT_F_EMPTY_PATH #define MOVE_MOUNT_F_EMPTY_PATH 0x00000004 #endif
#define WORK "/tmp/uc" #define ADIR WORK "/A"
static int duration = 60, nwalkers = 3; static atomic_int stop, writer_waiting; static pthread_rwlock_t cur_lock = PTHREAD_RWLOCK_INITIALIZER; static int cur_fd = -1; /* the root of A', -1 while there is none */ static atomic_long n_unlink, n_walk, n_mark, n_enoent, n_othe ---truncated---
Executive ViewAI
A race condition in the Linux kernel's virtual filesystem layer (CVE-2026-98980) could allow a local attacker with mount manipulation privileges to read files that are otherwise hidden by an overmount, potentially exposing sensitive data. While the vulnerability requires a very narrow timing window and privileged operations, it affects any Linux system where unprivileged user namespaces are enabled, making it relevant for multi-tenant or containerized environments. Leadership should prioritize patching to prevent potential data confidentiality breaches and maintain compliance with security best practices.
Apply vendor patch.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.
EUVD-2026-108774
GHSA-r8cp-fx7r-5fxq
NVD
CVE.org
EPSS
Exploit-DB