CVE-2026-99170 (GCVE-0-2026-99170)

Vulnerability from cvelistv5 – Published: 2026-10-28 10:35 – Updated: 2026-10-31 12:44
VLAI
Title
namespace: a mount that copy_tree() leaves out can't take over a lock
Summary
In the Linux kernel, the following vulnerability has been resolved: namespace: a mount that copy_tree() leaves out can't take over a lock Since commit c62a4766937e ("move_mount: transfer MNT_LOCKED") a mount can be moved beneath a locked mount. The lock moves from the old cover to the new mount which takes over the job of hiding what's under it and the old cover can be unmounted. That works as long as the new mount stays. But the caller picks the new mount and copy_tree() leaves a mount of a mount namespace file out of every copy made without CL_COPY_MNT_NS_FILE, together with everything mounted on it, and never looks at MNT_LOCKED. unshare(CLONE_NEWNS) and mount propagation make such copies. So a task that is root in its own user namespace gets rid of a locked cover on a file without a race and without touching the filesystem below it. It makes a child with a mount namespace of its own, binds the child's /proc/<pid>/ns/mnt beneath the cover with MOVE_MOUNT_BENEATH, which hands the lock to that bind, and calls unshare(CLONE_NEWNS). The new mount namespace has nothing on the file. That's the usual way to mask a single file, a bind of /dev/null or of an empty file. With a bind of an ordinary file the file stays covered. copy_tree() already refuses to leave out a locked unbindable mount with -EPERM since commit df7342b24018 ("mount: Don't allow copying MNT_UNBINDABLE|MNT_LOCKED mounts"). Do the same for a locked mount of a mount namespace file. That also covers a tree copied with CL_COPY_MNT_NS_FILE and attached into a mount namespace of another user namespace where lock_mnt_tree() locks it. Note that unshare(CLONE_NEWNS) and clone(CLONE_NEWNS) fail with EPERM from such a mount namespace from then on. The mount can't be left out and it can't be unmounted. And refuse to move a mount of a mount namespace file beneath a locked mount in the first place. Otherwise the task ends up with a mount it can't unmount and an unshare() that fails for good. Chris also found a second mount that goes away by itself, a clone of an automounted mount that shrink_submounts() took along with its parent. Commit f78ddcc87224 ("namespace: never expire a locked mount") took care of that one. Chris's reproducer is appended. Mode nsfile reads SECRET after the unshare() on 7.3-rc7, with this patch the move_mount() fails with EINVAL and the file stays covered. nsfile-control uses an ordinary file and reads MASK both ways. // SPDX-License-Identifier: GPL-2.0 /* * Get rid of a locked cover with MOVE_MOUNT_BENEATH. * * The "admin" (root) makes a tmpfs W: * W/D file, holds SECRET, covered by a bind of a file with MASK * W/Dd/inner file, holds SECRET, Dd is covered by a bind of a directory * whose "inner" holds MASK * W/own directory of uid 1000 with the file "mine" and the * directory "minedir", whose "inner" holds MINE * W/dbg debugfs, mode 755. dbg/tracing is an automount point * The "attacker" is uid 1000. It enters a new user namespace with a new mount * namespace, so W and both covers are locked there. * * usage: prog MODE * plain put a bind of own/mine beneath the cover of D, unmount the cover * nsfile put a bind of the mount namespace file of a child beneath the * cover of D, then unshare(CLONE_NEWNS) * nsfile-control the same with a bind of own/mine * shrink put a bind of the automounted tracefs beneath the cover of Dd, * unmount the cover, put a tmpfs beneath W, call umount(W), which fails * shrink-control the same with a bind of own/minedir * The environment variable AUTOMOUNT_DIR names another automount point for "shrink". */ #define _GNU_SOURCE #include <errno.h> #include <fcntl.h> #include <grp.h> #include <sched.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> ---truncated---
Assigner
Linux CNA under the mitre root
CNA scorecard D 53/100 over 6639 records in the last 180 days details
Impacted products
Vendor Product Version CPE status
Linux Linux Affected: c62a4766937edec2962d52e583276b459b739f2d , < bd71d33923b9d6216bcee44331dd37142b0a8441 (git)
Affected: c62a4766937edec2962d52e583276b459b739f2d , < 69fbe94f80bc423613fa18dae6656757423732a2 (git)
guessed Create a notification for this product.
Linux Linux Affected: 7.1
Unaffected: 0 , < 7.1 (semver)
Unaffected: 7.2.13 , ≤ 7.2.* (semver)
Unaffected: 7.3 , ≤ * (original_commit_for_fix)
guessed Create a notification for this product.
Show details on NVD website

{
  "containers": {
    "cna": {
      "affected": [
        {
          "defaultStatus": "unaffected",
          "product": "Linux",
          "programFiles": [
            "fs/namespace.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "lessThan": "bd71d33923b9d6216bcee44331dd37142b0a8441",
              "status": "affected",
              "version": "c62a4766937edec2962d52e583276b459b739f2d",
              "versionType": "git"
            },
            {
              "lessThan": "69fbe94f80bc423613fa18dae6656757423732a2",
              "status": "affected",
              "version": "c62a4766937edec2962d52e583276b459b739f2d",
              "versionType": "git"
            }
          ]
        },
        {
          "defaultStatus": "affected",
          "product": "Linux",
          "programFiles": [
            "fs/namespace.c"
          ],
          "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
          "vendor": "Linux",
          "versions": [
            {
              "status": "affected",
              "version": "7.1"
            },
            {
              "lessThan": "7.1",
              "status": "unaffected",
              "version": "0",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "7.2.*",
              "status": "unaffected",
              "version": "7.2.13",
              "versionType": "semver"
            },
            {
              "lessThanOrEqual": "*",
              "status": "unaffected",
              "version": "7.3",
              "versionType": "original_commit_for_fix"
            }
          ]
        }
      ],
      "cpeApplicability": [
        {
          "nodes": [
            {
              "cpeMatch": [
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.2.13",
                  "versionStartIncluding": "7.1",
                  "vulnerable": true
                },
                {
                  "criteria": "cpe:2.3:o:linux:linux_kernel:*:*:*:*:*:*:*:*",
                  "versionEndExcluding": "7.3",
                  "versionStartIncluding": "7.1",
                  "vulnerable": true
                }
              ],
              "negate": false,
              "operator": "OR"
            }
          ]
        }
      ],
      "descriptions": [
        {
          "lang": "en",
          "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nnamespace: a mount that copy_tree() leaves out can\u0027t take over a lock\n\nSince commit c62a4766937e (\"move_mount: transfer MNT_LOCKED\") a mount\ncan be moved beneath a locked mount. The lock moves from the old cover\nto the new mount which takes over the job of hiding what\u0027s under it and\nthe old cover can be unmounted. That works as long as the new mount\nstays. But the caller picks the new mount and copy_tree() leaves a\nmount of a mount namespace file out of every copy made without\nCL_COPY_MNT_NS_FILE, together with everything mounted on it, and never\nlooks at MNT_LOCKED. unshare(CLONE_NEWNS) and mount propagation make\nsuch copies.\n\nSo a task that is root in its own user namespace gets rid of a locked\ncover on a file without a race and without touching the filesystem\nbelow it. It makes a child with a mount namespace of its own, binds the\nchild\u0027s /proc/\u003cpid\u003e/ns/mnt beneath the cover with MOVE_MOUNT_BENEATH,\nwhich hands the lock to that bind, and calls unshare(CLONE_NEWNS). The\nnew mount namespace has nothing on the file. That\u0027s the usual way to\nmask a single file, a bind of /dev/null or of an empty file. With a\nbind of an ordinary file the file stays covered.\n\ncopy_tree() already refuses to leave out a locked unbindable mount with\n-EPERM since commit df7342b24018 (\"mount: Don\u0027t allow copying\nMNT_UNBINDABLE|MNT_LOCKED mounts\"). Do the same for a locked mount of a\nmount namespace file. That also covers a tree copied with\nCL_COPY_MNT_NS_FILE and attached into a mount namespace of another user\nnamespace where lock_mnt_tree() locks it. Note that unshare(CLONE_NEWNS)\nand clone(CLONE_NEWNS) fail with EPERM from such a mount namespace from\nthen on. The mount can\u0027t be left out and it can\u0027t be unmounted.\n\nAnd refuse to move a mount of a mount namespace file beneath a locked\nmount in the first place. Otherwise the task ends up with a mount it\ncan\u0027t unmount and an unshare() that fails for good.\n\nChris also found a second mount that goes away by itself, a clone of an\nautomounted mount that shrink_submounts() took along with its parent.\nCommit f78ddcc87224 (\"namespace: never expire a locked mount\") took\ncare of that one.\n\nChris\u0027s reproducer is appended. Mode nsfile reads SECRET after the\nunshare() on 7.3-rc7, with this patch the move_mount() fails with\nEINVAL and the file stays covered. nsfile-control uses an ordinary file\nand reads MASK both ways.\n\n  // SPDX-License-Identifier: GPL-2.0\n  /*\n   * Get rid of a locked cover with MOVE_MOUNT_BENEATH.\n   *\n   * The \"admin\" (root) makes a tmpfs W:\n   *     W/D         file, holds SECRET, covered by a bind of a file with MASK\n   *     W/Dd/inner  file, holds SECRET, Dd is covered by a bind of a directory\n   *                 whose \"inner\" holds MASK\n   *     W/own       directory of uid 1000 with the file \"mine\" and the\n   *                 directory \"minedir\", whose \"inner\" holds MINE\n   *     W/dbg       debugfs, mode 755. dbg/tracing is an automount point\n   * The \"attacker\" is uid 1000. It enters a new user namespace with a new mount\n   * namespace, so W and both covers are locked there.\n   *\n   * usage: prog MODE\n   *   plain      put a bind of own/mine beneath the cover of D, unmount the cover\n   *   nsfile     put a bind of the mount namespace file of a child beneath the\n   *              cover of D, then unshare(CLONE_NEWNS)\n   *   nsfile-control    the same with a bind of own/mine\n   *   shrink     put a bind of the automounted tracefs beneath the cover of Dd,\n   *              unmount the cover, put a tmpfs beneath W, call umount(W), which fails\n   *   shrink-control    the same with a bind of own/minedir\n   * The environment variable AUTOMOUNT_DIR names another automount point for \"shrink\".\n   */\n  #define _GNU_SOURCE\n  #include \u003cerrno.h\u003e\n  #include \u003cfcntl.h\u003e\n  #include \u003cgrp.h\u003e\n  #include \u003csched.h\u003e\n  #include \u003csignal.h\u003e\n  #include \u003cstdio.h\u003e\n  #include \u003cstdlib.h\u003e\n  #include \u003cstring.h\u003e\n  #include \u003cunistd.h\u003e\n \n---truncated---"
        }
      ],
      "metrics": [
        {
          "cvssV3_1": {
            "baseScore": 8.8,
            "baseSeverity": "HIGH",
            "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
            "version": "3.1"
          },
          "scenarios": [
            {
              "lang": "en",
              "value": "AV:L - Local move_mount(2) reaches do_move_mount()-\u003ecan_move_mount_beneath(), and unshare(2) reaches copy_mnt_ns()-\u003ecopy_tree(), the two functions patched; no network input reaches either path.\nAC:L - Given an inherited locked file cover, the attacker creates its own child namespace, clones /proc/\u003cpid\u003e/ns/mnt, moves it beneath the cover, and calls unshare(CLONE_NEWNS). The sequence deterministically makes copy_tree() omit the locked replacement and requires no race.\nPR:L - open_tree(OPEN_TREE_CLONE) and move_mount() require may_mount(), which checks CAP_SYS_ADMIN in the mount namespace\u0027s owning user namespace; an ordinary user obtains it with unshare(CLONE_NEWUSER|CLONE_NEWNS), and ptrace_may_access() permits its own child namespace file.\nUI:N - The attacker independently forks the child and invokes open_tree(), move_mount(MOVE_MOUNT_BENEATH), unshare(), and the final file access after entering the sandbox; no victim action is induced.\nS:C - lock_mnt_tree() applies MNT_LOCKED when copying a mount tree into a less-privileged user namespace specifically to conceal parent resources; defeating that lock exposes a file across the parent-imposed mount-namespace sandbox boundary.\nC:H - Vulnerable copy_tree() skips the mount-namespace-file mount and everything mounted above it, so path lookup reaches the complete underlying file. In a same-identity sandbox where the locked cover is the access-control boundary, the attacker can read an arbitrarily large sensitive file.\nI:H - After copy_tree() removes the cover, open(O_WRONLY|O_TRUNC) reaches do_open()-\u003ehandle_truncate()-\u003edo_truncate(); where underlying DAC permits the sandbox identity, the attacker can replace or erase the entire file that MNT_LOCKED was intended to protect.\nA:H - The same exposed-file primitive can truncate a covered executable, configuration, or database through handle_truncate(), causing complete and persistent loss of the dependent service when that file is availability-critical."
            }
          ]
        }
      ],
      "providerMetadata": {
        "dateUpdated": "2026-10-31T12:44:35.158Z",
        "orgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "shortName": "Linux"
      },
      "references": [
        {
          "url": "https://git.kernel.org/stable/c/bd71d33923b9d6216bcee44331dd37142b0a8441"
        },
        {
          "url": "https://git.kernel.org/stable/c/69fbe94f80bc423613fa18dae6656757423732a2"
        }
      ],
      "title": "namespace: a mount that copy_tree() leaves out can\u0027t take over a lock",
      "x_generator": {
        "engine": "bippy-1.2.0"
      }
    }
  },
  "cveMetadata": {
    "assignerOrgId": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
    "assignerShortName": "Linux",
    "cveId": "CVE-2026-99170",
    "datePublished": "2026-10-28T10:35:25.923Z",
    "dateReserved": "2026-09-25T10:25:14.398Z",
    "dateUpdated": "2026-10-31T12:44:35.158Z",
    "state": "PUBLISHED"
  },
  "dataType": "CVE_RECORD",
  "dataVersion": "5.2",
  "vulnerability-lookup:meta": {
    "epss": {
      "cve": "CVE-2026-99170",
      "date": "2026-11-09",
      "epss": "0.0013",
      "percentile": "0.02632"
    },
    "nvd": {
      "cve": {
        "affected": [
          {
            "affectedData": [
              {
                "defaultStatus": "unaffected",
                "product": "Linux",
                "programFiles": [
                  "fs/namespace.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "lessThan": "bd71d33923b9d6216bcee44331dd37142b0a8441",
                    "status": "affected",
                    "version": "c62a4766937edec2962d52e583276b459b739f2d",
                    "versionType": "git"
                  },
                  {
                    "lessThan": "69fbe94f80bc423613fa18dae6656757423732a2",
                    "status": "affected",
                    "version": "c62a4766937edec2962d52e583276b459b739f2d",
                    "versionType": "git"
                  }
                ]
              },
              {
                "defaultStatus": "affected",
                "product": "Linux",
                "programFiles": [
                  "fs/namespace.c"
                ],
                "repo": "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git",
                "vendor": "Linux",
                "versions": [
                  {
                    "status": "affected",
                    "version": "7.1"
                  },
                  {
                    "lessThan": "7.1",
                    "status": "unaffected",
                    "version": "0",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "7.2.*",
                    "status": "unaffected",
                    "version": "7.2.13",
                    "versionType": "semver"
                  },
                  {
                    "lessThanOrEqual": "*",
                    "status": "unaffected",
                    "version": "7.3",
                    "versionType": "original_commit_for_fix"
                  }
                ]
              }
            ],
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67"
          }
        ],
        "cveTags": [],
        "descriptions": [
          {
            "lang": "en",
            "value": "In the Linux kernel, the following vulnerability has been resolved:\n\nnamespace: a mount that copy_tree() leaves out can\u0027t take over a lock\n\nSince commit c62a4766937e (\"move_mount: transfer MNT_LOCKED\") a mount\ncan be moved beneath a locked mount. The lock moves from the old cover\nto the new mount which takes over the job of hiding what\u0027s under it and\nthe old cover can be unmounted. That works as long as the new mount\nstays. But the caller picks the new mount and copy_tree() leaves a\nmount of a mount namespace file out of every copy made without\nCL_COPY_MNT_NS_FILE, together with everything mounted on it, and never\nlooks at MNT_LOCKED. unshare(CLONE_NEWNS) and mount propagation make\nsuch copies.\n\nSo a task that is root in its own user namespace gets rid of a locked\ncover on a file without a race and without touching the filesystem\nbelow it. It makes a child with a mount namespace of its own, binds the\nchild\u0027s /proc/\u003cpid\u003e/ns/mnt beneath the cover with MOVE_MOUNT_BENEATH,\nwhich hands the lock to that bind, and calls unshare(CLONE_NEWNS). The\nnew mount namespace has nothing on the file. That\u0027s the usual way to\nmask a single file, a bind of /dev/null or of an empty file. With a\nbind of an ordinary file the file stays covered.\n\ncopy_tree() already refuses to leave out a locked unbindable mount with\n-EPERM since commit df7342b24018 (\"mount: Don\u0027t allow copying\nMNT_UNBINDABLE|MNT_LOCKED mounts\"). Do the same for a locked mount of a\nmount namespace file. That also covers a tree copied with\nCL_COPY_MNT_NS_FILE and attached into a mount namespace of another user\nnamespace where lock_mnt_tree() locks it. Note that unshare(CLONE_NEWNS)\nand clone(CLONE_NEWNS) fail with EPERM from such a mount namespace from\nthen on. The mount can\u0027t be left out and it can\u0027t be unmounted.\n\nAnd refuse to move a mount of a mount namespace file beneath a locked\nmount in the first place. Otherwise the task ends up with a mount it\ncan\u0027t unmount and an unshare() that fails for good.\n\nChris also found a second mount that goes away by itself, a clone of an\nautomounted mount that shrink_submounts() took along with its parent.\nCommit f78ddcc87224 (\"namespace: never expire a locked mount\") took\ncare of that one.\n\nChris\u0027s reproducer is appended. Mode nsfile reads SECRET after the\nunshare() on 7.3-rc7, with this patch the move_mount() fails with\nEINVAL and the file stays covered. nsfile-control uses an ordinary file\nand reads MASK both ways.\n\n  // SPDX-License-Identifier: GPL-2.0\n  /*\n   * Get rid of a locked cover with MOVE_MOUNT_BENEATH.\n   *\n   * The \"admin\" (root) makes a tmpfs W:\n   *     W/D         file, holds SECRET, covered by a bind of a file with MASK\n   *     W/Dd/inner  file, holds SECRET, Dd is covered by a bind of a directory\n   *                 whose \"inner\" holds MASK\n   *     W/own       directory of uid 1000 with the file \"mine\" and the\n   *                 directory \"minedir\", whose \"inner\" holds MINE\n   *     W/dbg       debugfs, mode 755. dbg/tracing is an automount point\n   * The \"attacker\" is uid 1000. It enters a new user namespace with a new mount\n   * namespace, so W and both covers are locked there.\n   *\n   * usage: prog MODE\n   *   plain      put a bind of own/mine beneath the cover of D, unmount the cover\n   *   nsfile     put a bind of the mount namespace file of a child beneath the\n   *              cover of D, then unshare(CLONE_NEWNS)\n   *   nsfile-control    the same with a bind of own/mine\n   *   shrink     put a bind of the automounted tracefs beneath the cover of Dd,\n   *              unmount the cover, put a tmpfs beneath W, call umount(W), which fails\n   *   shrink-control    the same with a bind of own/minedir\n   * The environment variable AUTOMOUNT_DIR names another automount point for \"shrink\".\n   */\n  #define _GNU_SOURCE\n  #include \u003cerrno.h\u003e\n  #include \u003cfcntl.h\u003e\n  #include \u003cgrp.h\u003e\n  #include \u003csched.h\u003e\n  #include \u003csignal.h\u003e\n  #include \u003cstdio.h\u003e\n  #include \u003cstdlib.h\u003e\n  #include \u003cstring.h\u003e\n  #include \u003cunistd.h\u003e\n \n---truncated---"
          }
        ],
        "id": "CVE-2026-99170",
        "lastModified": "2026-10-31T13:17:58.570",
        "metrics": {
          "cvssMetricV31": [
            {
              "cvssData": {
                "attackComplexity": "LOW",
                "attackVector": "LOCAL",
                "availabilityImpact": "HIGH",
                "baseScore": 8.8,
                "baseSeverity": "HIGH",
                "confidentialityImpact": "HIGH",
                "integrityImpact": "HIGH",
                "privilegesRequired": "LOW",
                "scope": "CHANGED",
                "userInteraction": "NONE",
                "vectorString": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
                "version": "3.1"
              },
              "exploitabilityScore": 2.0,
              "impactScore": 6.0,
              "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
              "type": "Secondary"
            }
          ]
        },
        "published": "2026-10-28T11:17:37.520",
        "references": [
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/69fbe94f80bc423613fa18dae6656757423732a2"
          },
          {
            "source": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
            "url": "https://git.kernel.org/stable/c/bd71d33923b9d6216bcee44331dd37142b0a8441"
          }
        ],
        "sourceIdentifier": "416baaa9-dc9f-4396-8d5f-8c081fb06d67",
        "vulnStatus": "Received"
      }
    },
    "redhat_vex": {
      "aggregate_severity": "Moderate",
      "current_release_date": "2026-11-06T03:27:42+00:00",
      "cve": "CVE-2026-99170",
      "id": "CVE-2026-99170",
      "initial_release_date": "2026-10-28T00:00:00+00:00",
      "product_status:known_affected": "14",
      "product_status:known_not_affected": "189",
      "source": "Red Hat CSAF VEX",
      "status": "final",
      "title": "kernel: namespace: a mount that copy_tree() leaves out can\u0027t take over a lock",
      "url": "https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-99170.json",
      "version": "3"
    }
  }
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Drag nodes to arrange them. Double-click a related vulnerability to open it, or a source to visit its link. The Physics button on the left tunes the layout and the simulation; the legend at the bottom left hides or shows nodes by kind and by sighting type.

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
Vulnerability timeline

Sightings and recorded dates, grouped by day · UTC

JSON
How durations are calculated

Following the VTEM framework (Black Hat USA 2015), time to patch starts when the vendor or a coordinator was informed, total time to patch at discovery, and disclosure to patch at public disclosure; vendor response time runs from the report to its acknowledgement. Time to exploit and time unpatched start at the earliest discovery or report, falling back to public disclosure. Unpatched time ends at the first recorded patch, or the calculation time when no patch is recorded. Exploitation to patch shows the interval between those two events; a published proof of concept is a public exploit, not exploitation.

Each result shows its source dates. A negative interval means the end event came first; when date-only inputs leave the order open, the result says so. Date-only inputs are approximate. The earliest evidence wins: KEV report dates and sightings are labelled as such. Records describing another vulnerability are listed but never calculated from, and a PoC alone does not establish exploitation. Missing patch evidence does not prove that no patch exists. Filters below change the event list only.

Events included in the timeline

Loading timeline…


    Loading…

    Loading…

    Loading…

    Related by attack behaviour

    Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.