Tech

Jul 24, 2026

 · 

5

 min read

Oh Snap: Preventing CVE-2026-8933 at runtime with Photon

Summary

On July 21, 2026, the Qualys Threat Research Unit disclosed CVE-2026-8933 - (7.8 HIGH), a local privilege escalation in snap-confine, the helper that snapd uses to construct the execution environment for snap applications. On affected systems — including default installations of Ubuntu Desktop 24.04, 25.10, and 26.04 — an unprivileged local user can obtain full root. The discovery and analysis are the results of the great work of the Qualys team.

This article dissects the vulnerability and the upstream fix, then shows how Exein Photon neutralizes it at runtime: a single detection rule reproduces the protective effect of the snapd upstream fix with no package update, no reboot, and no downtime. We validated the approach on a stock Ubuntu virtual machine running a pre-fix version of snapd.

Root cause

Ubuntu transitioned /usr/lib/snapd/snap-confine from a setuid-root binary to a file-capabilities binary.

This change altered an implicit invariant. A setuid-root process executes as root, so any file or directory it creates is owned by root. A capabilities-based process instead retains the caller's user identity while holding privileged capabilities such as CAP_DAC_OVERRIDE. Consequently, snap-confine now creates filesystem objects owned by the invoking unprivileged user, while still holding the ability to write to otherwise protected locations.

The vulnerability

During sandbox construction, snap-confine creates a scratch directory, /tmp/snap.rootfs_XXXXXX, and replicates the base snap's root filesystem into it. For each regular file in the base, it creates an empty mount-point file:

// cmd/snap-confine/mount-support.c, sc_replicate_base_rootfs()
int fd = open(full_path, O_CREAT | O_TRUNC, 0644);

The open() call does not specify O_NOFOLLOW. Because the scratch directory is transiently owned by the unprivileged user, an attacker who wins a TOC-TOU race can place a symbolic link at full_path. As snap-confine executes with CAP_DAC_OVERRIDE and without O_NOFOLLOW, it follows the link and creates the target file. As described by Qualys, this primitive can be directed at /run/udev/rules.d/, where a crafted .rules file containing a PROGRAM= directive is subsequently executed as root by systemd-udevd.

The upstream fix

The corresponding fix, commit 2cafc7a, adds the omitted flag:

int fd = open(full_path, O_CREAT | O_TRUNC | O_NOFOLLOW, 0644);

The fix was released in snapd 2.76.1.

Runtime patching: enforcing the fix with Photon

Detection establishes whether a host is exposed; prevention closes the exposure. Exein Photon adjudicates at the LSM layer can enforce the flag's effect — refusing an open that has followed a symbolic link. The upstream fix guarantees that the mount-point creation never leaves the scratch directory; the following rule enforces the same invariant by denying any snap-confine open whose resolved path lies outside it:

[[rules]]
name        = "CVE-2026-8933, virtual patch—deny snap-confine escape scratch dir"
type        = "file_open"
category    = "privilege_escalation"
severity    = "high"
description = "Reproduces the effect of the snapd 2.76.1 fix at runtime: denies a snap-confine O_CREAT open (without O_NOFOLLOW) whose resolved path is outside /tmp/snap.rootfs_*"
condition   = '''header.image.name == "snap-confine" &&
payload.flags.contains("O_CREAT") &&
!payload.flags.contains("O_NOFOLLOW") &&
!payload.file_path.abs.starts_with("/tmp/snap.rootfs_")'''
action      = "block"

The rule reads directly as the invariant it enforces. The header.image.name == "snap-confine" scopes it to the vulnerable binary; payload.flags.contains("O_CREAT") && !payload.flags.contains("O_NOFOLLOW") isolates the exact unsafe open and !payload.file_path.abs.starts_with("/tmp/snap.rootfs_") fires only when the resolved path escapes the scratch directory — i.e. a planted symlink was followed.

The rule constrains that single operation: snap-confine may create a file with O_CREAT and no O_NOFOLLOW only when the resolved path remains inside its own /tmp/snap.rootfs_* scratch directory (Legitimate replication creates files only within /tmp/snap.rootfs_*).

On the vulnerable VM we confirmed that a normal snap launch is unaffected with the rule active — snap run completes successfully and snap-confine generates no denial — while an open that escapes the scratch directory is refused with EPERM.

[4528081843986 THREAT /usr/lib/snapd/snap-confine (11132)] [RULE ENGINE (block) - CVE-2026-8933, deny snap-confine escape scratch dir]
{
  "header": {
    "image": {
      "abs": "/usr/lib/snapd/snap-confine",
      "name": "snap-confine"
    },
    "pid": 11132,
    "bpf_timestamp": 4528081843986
  },
  "payload": {
    "type": "FileOpen",
    "value": {
      "file_path": {
        "abs": "/tmp/scratch-escape",
        "name": "scratch-escape"
      },
      "flags": 33345
    }
  }
}

Conclusion

Applying the vendor patch remains the definitive remediation. In practice, however, patching a fleet is a process rather than a discrete event. During the interval between disclosure and complete remediation, two questions are operationally significant: which hosts remain exploitable, and whether the vulnerable path is being exercised. A single Photon rule provides evidence for both.

Local privilege escalation vulnerabilities are consistently inexpensive to weaponize and costly to investigate retrospectively. Runtime visibility at the kernel boundary is an effective means of closing the exposure window while remediation proceeds.

To evaluate Photon against this vulnerability or your own detection requirements, contact the Exein team for a demo.

Share this resource
By subscribing, you agree to Exein’s Privacy Policy.
Thank you for your interest.
Download
Your download will begin automatically. If it doesn’t,

click here to download it manually.
Oops! Something went wrong while submitting the form.
Subscribe to our newsletter
By subscribing, you agree to Exein’s Privacy Policy.
You’re subscribed
We’ll keep you updated with the latest from Exein.
Oops! Something went wrong while submitting the form.

Built by you, trusted by your customers, secured by Exein

No items found.
No items found.
No items found.