A graphics server forgets to put down its pen before someone else grabs it
CVE-2025-26599 is an uninitialized pointer dereference in the X.Org server's device handling code path (the Xkb / device event plumbing shared with Xwayland). When a local client sends a crafted sequence of input device requests, the server reads a stack/heap slot that was never initialized, giving a controlled value that can be steered into a write primitive. Affected: xorg-server before 21.1.16 and xwayland before 24.1.6, plus all distro packages built from those trees (RHEL 7/8/9, Ubuntu 20.04/22.04/24.04, Debian bullseye/bookworm, SUSE 15.x). The fix landed in the X.Org 21.1.16 release alongside a batch of six sibling memory-safety CVEs (CVE-2025-26594 through 26600) reported by Trend Micro Zero Day Initiative.
Vendor severity of HIGH (7.8) is *defensible but inflated for the typical enterprise host*. The CVSS vector AV:L/AC:L/PR:L/UI:N/C:H/I:H/A:H is honest — it correctly captures that this is local-only with low-privileged auth required. The score assumes the affected machine is a multi-user desktop where unprivileged users routinely have an X session. That describes a *narrow slice* of an enterprise fleet: lab boxes, jump hosts, RHV/RHEL Workstation, Linux engineer laptops. On the 90%+ of Linux installs that are headless servers with no Xorg running, this CVE is *inert*.
4 steps from start to impact.
Land a local session on a host running Xorg or Xwayland
/tmp/.X11-unix/X0) or to Xwayland via the user's session. This is the precondition that defines the entire CVE class — no X server, no bug.- Local code execution as any UID
- Xorg or Xwayland process active
- Access to the X socket (same user, or
xhost +misconfig)
- Headless servers do not run Xorg at all
- Server-class RHEL/Ubuntu minimal images do not install xorg-server
- MAC (SELinux, AppArmor) confines unconfined_t shells away from the X socket in some hardened builds
xorg-x11-server-cve-2025-26599 all detect by package version. Nessus credentialed scan catches it cleanly.Open an X connection and issue the trigger request
DISPLAY=:0, then issues the malformed device / Xkb extension request sequence that walks the uninitialized pointer. ZDI's disclosure references a PoC pattern shared across the Feb 2025 X.Org batch (xkb_swap_* family).- Xlib/XCB available or static binary
- Display reachable from attacker's UID
- With per-user Wayland sessions and no Xwayland fallback, no socket exists
- GNOME/KDE on modern Wayland-by-default distros do not run rootful Xorg
connect() to X sockets from unexpected binaries.Convert uninitialized read into a controlled write
XIChangeDeviceProperty, OOB write in XISendDeviceHierarchyEvent), a reliable write-what-where becomes practical. ZDI rated this exploitable.- Heap groom feasibility (typical glibc layout)
- No CFI on Xorg binary (default on stock distro builds)
- Distro builds with
-fstack-protector-strong,-D_FORTIFY_SOURCE=2, full RELRO reduce reliability - Xorg runs as root on classic deployments but as the user under
Xorg.wrap+ systemd-logind on modern distros — root drop changes the prize
Escalate to root (classic Xorg) or to session compromise (Xwayland / rootless)
CAP_SYS_RAWIO, the write primitive yields root. On modern Wayland-by-default systems where Xwayland runs as the logged-in user, the primitive yields session-level code execution — equivalent privilege to the user but with access to all their sessions, keyrings, and SSH agent.- Setuid Xorg OR session containing valuable credentials
- Fedora 36+, Ubuntu 21.04+, RHEL 9 default to rootless Xorg / Wayland — root is no longer the prize
- Locked-down kiosk hosts have no creds worth stealing
execve from xorg uid, EDR (CrowdStrike, SentinelOne, Defender for Endpoint Linux) flags post-exploit behaviour, not the primitive.The supporting signals.
| In-the-wild status | No known exploitation. Not on CISA KEV. No incident reports from Mandiant, CrowdStrike Falcon Intel, or Red Canary as of disclosure batch review. |
|---|---|
| Public PoC | No fully weaponized public PoC. ZDI advisory ZDI-25-117 describes the bug class; trigger snippets exist in the X.Org commit history (xserver mainline patch xkb: Fix buffer overflow in _XkbSetCompatMap-adjacent commits). |
| EPSS | 0.0036 (≈ 0.4 percentile) — FIRST.org models it as essentially never exploited in the wild. |
| KEV | Not listed. No CISA action. |
| CVSS v3.1 | AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H → 7.8 HIGH. Local attack vector is the key constraint. |
| CWE | CWE-824 — Access of Uninitialized Pointer. |
| Affected | xorg-server < 21.1.16, xwayland < 24.1.6, plus distro builds (RHEL xorg-x11-server pre-backport, Ubuntu xorg-server pre-USN-7244-1, Debian DSA-5860-1, SUSE SUSE-SU-2025:0683). |
| Fixed | Upstream 21.1.16 / xwayland 24.1.6. Distro backports: RHEL xorg-x11-server-1.20.11-25.el8_10, Ubuntu 2:21.1.4-2ubuntu1.7~22.04.13, Debian 2:1.20.11-1+deb11u14. |
| Exposure | Shodan/Censys do not index local X sockets. GreyNoise N/A — not network-reachable. Internal estimate: 5-15% of a typical Linux fleet runs Xorg/Xwayland (engineering workstations, jump hosts, lab); ~85% headless servers are unaffected at runtime even when the package is installed. |
| Reporter | Trend Micro Zero Day Initiative, part of the Feb 2025 X.Org coordinated batch (CVE-2025-26594 through CVE-2025-26600). |
noisgate verdict.
Downgraded one bucket because the attack vector is local with prior authenticated access required — the chain assumes the attacker already has a shell on the host, which is post-initial-access territory. The X.Org/Xwayland role is a user-facing desktop component with no fleet-level blast radius: compromise stays on a single host and, on modern rootless stacks, does not even cross the user boundary.
Why this verdict
- Local-only vector (
AV:L) — attacker must already have a shell. This is an LPE, not an RCE. Subtract one bucket from the vendor's vector-blind 7.8. - Exposure narrowing — on a 10,000-host fleet, the realistic affected population is the desktop / jump host slice (~10-20%). Servers patch the package via routine OS updates but never load the vulnerable code.
- Role multiplier: low-value role (workstation, dev sandbox) — chain succeeds, blast radius is *single user's session* on modern rootless Xorg. No lateral movement primitive from this CVE alone.
- Role multiplier: typical role (multi-user jump host, bastion, shared engineering box) — chain succeeds, blast radius is *root on that host* if legacy setuid Xorg, otherwise session-level. Still host-scoped, no domain pivot.
- Role multiplier: high-value role — Xorg is not canonically deployed on identity, hypervisor, PKI, backup, or CI/CD control planes. Where it is (admin workstation with vSphere/Vault TUI cached creds), the blast radius is the *operator's session*, not the platform — but this argues for hardening admin workstations, not floor-raising this CVE.
- No KEV, EPSS 0.36%, no public weaponized PoC — no active campaign pressure to override the friction discount.
Why not higher?
Not HIGH because the vendor's 7.8 already prices in C:H/I:H/A:H against a hypothetical multi-user desktop. In an enterprise fleet that ratio is inverted — most hosts have no X server at runtime — and the chain requires prior local access, so the effective risk is materially below the 7.0 HIGH threshold. No KEV, no observed exploitation, no fleet-scale blast radius keep it below HIGH.
Why not lower?
Not LOW because on engineering workstations and shared multi-user Linux hosts this is a reliable LPE primitive, and the package is installed on a meaningful slice of the fleet. Six sibling CVEs in the same batch raise the chance one of them gets weaponized publicly, which would re-rate this class quickly. MEDIUM with a 365-day patch window — but not backlog-only.
What to do — in priority order.
- Remove xorg-server from headless servers — If
systemctl get-defaultismulti-user.targetand no admin usesssh -X, uninstallxorg-x11-server-Xorg/xserver-xorg-core. Eliminates the attack surface entirely. Do this within the 365-day noisgate remediation SLA; no mitigation SLA applies at MEDIUM. - Disable Xwayland fallback where Wayland is exclusive — On GNOME/KDE Wayland sessions, set
DISABLE_WAYLAND=0and removexwaylandpackage on hosts that have no legacy X11 client requirement. Reduces the runtime attack surface to zero on modern desktops. - Enforce per-user X authorization — Audit for
xhost +in/etc/X11/xinit/*and user dotfiles. EnsureMIT-MAGIC-COOKIE-1is the auth method and/tmp/.X11-unixis mode 1777 with sticky bit intact. Blocks cross-user socket access on shared hosts. - Apply distro patches in the next monthly cycle — RHEL, Ubuntu, Debian, SUSE all shipped backports within ~2 weeks of disclosure. Include in your standard OS patch ring — no out-of-band rollout needed at MEDIUM.
- Restrict interactive logins on shared jump hosts — Move jump-host workflows to ephemeral SSH bastions or session brokers (Teleport, Boundary). Removes the precondition of multiple concurrent local sessions on one X server.
- Network ACLs / firewall rules — vector is
AV:L. Nothing on the wire to filter. - WAF / reverse proxy controls — X11 is not HTTP and is not exposed externally on any sane deployment.
- Disabling X11 forwarding in sshd (
X11Forwarding no) — protects against remote-X-via-SSH abuse but does not stop a local attacker who already has a shell from talking to a locally-running Xorg. - EDR behavioral rules alone — there is no characteristic syscall pattern for the uninitialized-pointer trigger; EDR catches post-exploit, not the primitive.
Crowdsourced verification payload.
Run on each Linux target as root or via sudo (needs to read package DB and check whether Xorg is actually running). Invoke as sudo ./check-cve-2025-26599.sh. Exits 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN. Output also includes whether Xorg/Xwayland is *running* — if not, the host is effectively not exploitable even when the package is present.
#!/usr/bin/env bash
# noisgate check: CVE-2025-26599 (X.Org / Xwayland uninitialized pointer LPE)
# Exit: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
VULN=2
RUNNING="no"
ver_ge() {
# returns 0 if $1 >= $2 (dpkg-style compare, fallback to sort -V)
if command -v dpkg >/dev/null 2>&1; then
dpkg --compare-versions "$1" ge "$2"
else
[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -n1)" = "$2" ]
fi
}
check_pkg() {
local name="$1" fixed="$2" cur=""
if command -v rpm >/dev/null 2>&1; then
cur=$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' "$name" 2>/dev/null | head -n1)
elif command -v dpkg-query >/dev/null 2>&1; then
cur=$(dpkg-query -W -f='${Version}\n' "$name" 2>/dev/null | head -n1)
fi
[ -z "$cur" ] && return 2
echo " $name installed: $cur (fixed >= $fixed)"
if ver_ge "$cur" "$fixed"; then return 0; else return 1; fi
}
echo "[*] Checking xorg-server and xwayland packages..."
for entry in \
"xorg-x11-server-Xorg:1.20.11-25" \
"xserver-xorg-core:2:21.1.4-2ubuntu1.7" \
"xwayland:24.1.6" \
"xorg-x11-server-Xwayland:24.1.6"; do
pkg="${entry%%:*}"
fix="${entry#*:}"
check_pkg "$pkg" "$fix"
rc=$?
case $rc in
0) [ "$VULN" -ne 1 ] && VULN=0 ;;
1) VULN=1 ;;
esac
done
if pgrep -x Xorg >/dev/null 2>&1 || pgrep -x Xwayland >/dev/null 2>&1; then
RUNNING="yes"
fi
echo "[*] Xorg/Xwayland currently running: $RUNNING"
case $VULN in
0) echo "PATCHED"; exit 0 ;;
1) if [ "$RUNNING" = "yes" ]; then
echo "VULNERABLE (runtime exposure: YES)"
else
echo "VULNERABLE (runtime exposure: NO — package present but X server not running)"
fi
exit 1 ;;
*) echo "UNKNOWN (xorg/xwayland not installed or package manager not detected)"; exit 2 ;;
esac
If you remember one thing.
xorg-server/xwayland is *both installed and running* — that's your real exposure cohort (typically engineering workstations, shared jump hosts, lab/QA boxes). Per the noisgate mitigation SLA there is no mitigation deadline at MEDIUM — go straight to the noisgate remediation SLA of ≤ 365 days, which in practice means folding the distro backport into your next monthly OS patch ring. Prioritize multi-user jump hosts and any host still on legacy setuid Xorg ahead of single-user laptops. On headless servers, take the opportunity to *uninstall* xorg-server entirely rather than patching it — that closes the door on this whole CVE family (the other five sibling CVEs from the same Feb 2025 batch ship in the same package).Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.