---
id: "CVE-2026-98976"
kind: "vulnerability"
aliases: ["CVE-2026-98976"]
title: "Linux kernel: mount propagation lets a user namespace reveal covered files"
severity: "medium"
cvss: null
epss: 0.00198
exploited: false
status: "open"
category: "infrastructure"
products: []
ecosystems: []
tags: ["containers", "infrastructure", "linux-kernel", "user-namespaces"]
not_affected_if: ["default-config"]
published_at: "2026-10-23T13:17:19+00:00"
first_seen_at: "2026-10-23T21:57:33+00:00"
updated_at: "2026-10-25T12:38:50+00:00"
sources: [{"source": "nvd", "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-98976", "first_seen_at": "2026-10-23T21:57:33+00:00"}, {"source": "epss", "url": "https://api.first.org/data/v1/epss?cve=CVE-2026-98976", "first_seen_at": "2026-10-25T12:38:50+00:00"}]
---

# Linux kernel: mount propagation lets a user namespace reveal covered files

In the Linux kernel, mount propagation can unlock a locked mount covering a directory, so a user namespace owner can unmount the cover and read files underneath, such as a secret in P/d. The fix keeps the lock on the mount beneath a propagated copy so the cover stays locked.

_Summary, check and fix written by a model from the sources; labelled as such._

## Timeline

- 2026-10-23T21:57:33+00:00 nvd https://nvd.nist.gov/vuln/detail/CVE-2026-98976
- 2026-10-25T12:38:50+00:00 epss https://api.first.org/data/v1/epss?cve=CVE-2026-98976

## From the sources

In the Linux kernel, the following vulnerability has been resolved:

namespace: keep the lock on a mount that a propagated copy is moved beneath

attach_recursive_mnt() transfers MNT_LOCKED from the top mount to the
mount that is moved beneath it with MOVE_MOUNT_BENEATH. This allows the
owner of a user namespace to replace its locked /proc or its root. The
mount beneath takes on the job of covering the underlying mountpoint
allowing the top mount to be unmounted.

Consider two mount namespaces:

(H) The host H has a shared mount P with a secret in P/d
(Z) Z is a user namespace made from M. Its copy of P receives
    propagation from the host's P and its copy of M's cover on P/d is
    locked Z's owner must not get to see P/d.

Now (H) mounts X on P/d. This propagates into (Z). The copy of X lands
beneath (Z)'s locked cover. The locked property is transfered from (Z)'s
cover to the copy of X propagated beneath it. The cover is now unlocked.

Now (H) unmounts X again. The copy of X in (Z) gets unmounted and the
covering mount is left unlocked on top of P/d. (Z) can now unmount it:

    Z: umount2(P/d)             = EINVAL            /* the cover is locked */
    H: mount X on P/d, umount X                     /* both propagate into Z /*
    Z: umount2(P/d)             = 0                 /* the cover is now unlocked */
    Z: read P/d/secret          = "covered-by-root" /* secret revealed */

So only transfer the locked property to the mount beneath for mounts the
caller has placed. A propagated copy that lands beneath a locked mount
is locked as well so that the mount at the bottom of the stack carries a
lock the way every check expects. The mount on top of it remains locked
to ensure that it keeps covering even if the propagated mount is
unmounted again.

---

_Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai_
