This is a bad elevator in the staff-only hallway, not an unlocked front door
CVE-2025-26597 is a heap/buffer overflow in XkbChangeTypesOfKey() in X.Org Server and Xwayland. The bug appears when the function is first driven with groups=0, shrinking the key symbols table to zero while leaving key actions sized for the old layout; a later non-zero groups call can then overflow the actions buffer. Upstream fixes landed in xorg-server 21.1.16 and xwayland 24.1.6, while distros backported patches into their own package streams such as Ubuntu xserver-xorg-core and Debian security updates.
The vendor's 7.8/HIGH score is technically fair for the memory-corruption impact, but it overstates operational urgency for most enterprises. This is a local, post-initial-access flaw that requires low-privileged code execution on a Linux host running X.Org/Xwayland, and modern deployments often run Xorg rootless or use Xwayland in the logged-in user's context, which sharply reduces blast radius from 'root LPE everywhere' to 'useful only on a subset of workstation/VDI/VNC systems.'
4 steps from start to impact.
Get code execution on a GUI-capable Linux host
- Low-privileged code execution on the target host
- Target is running Linux/Unix with X.Org or Xwayland components present
- This implies the attacker has already cleared initial access
- Headless servers and many containerized workloads do not run X.Org/Xwayland at all
Reach the XKB code path in the display stack
XkbChangeTypesOfKey() path. In practice that means a local desktop, VDI seat, kiosk, remote GUI service, or VNC/X11-enabled workflow where the attacker can talk to the display server from their session.- An accessible X.Org or Xwayland process
- Ability to send crafted XKB requests from the local context
- Wayland-heavy environments reduce direct exposure to classic rootful Xorg
- Session isolation, sandboxing, and missing display access can block low-value footholds from reaching the vulnerable server
Trigger the zero-group then non-zero-group state mismatch
XkbChangeTypesOfKey() first with groups=0 to desynchronize buffer sizes, then again with a non-zero group count to overflow the heap buffer. The primitive is memory corruption inside the display server, which can produce crashes or controlled overwrite depending on allocator state and hardening.- Precise control of XKB requests
- Target build and runtime state conducive to stable corruption
- Reliable exploitation is harder than crashing the server
- Heap behavior, distro hardening, and process sandboxing reduce exploit reliability
Execute in the display server's security context
- Successful memory-corruption exploitation
- Vulnerable server running with privileges worth escalating into
- Rootless Xorg defaults and Xwayland user-context execution often cap the impact
- Even when Xorg is installed, many enterprise Linux servers never expose a privileged graphical session
The supporting signals.
| In-the-wild status | No confirmed active exploitation found in the sources reviewed; not present in CISA KEV. |
|---|---|
| Public PoC availability | No public PoC identified from vendor/ZDI-linked material or major public exploit indexes reviewed as of this assessment. |
| EPSS | 0.00029 from the supplied intel — effectively near-floor exploit probability in the next 30 days. |
| KEV status | Not KEV-listed; CISA's KEV catalog does not include CVE-2025-26597. |
| CVSS meaning | AV:L/AC:L/PR:L/UI:N means local attacker, low complexity, low privileges, no clicks — classic post-compromise LPE scoring. |
| Affected versions | Upstream fixed releases indicate affected upstream lines are before xorg-server 21.1.16 and before xwayland 24.1.6. |
| Fixed versions | Upstream: xorg-server 21.1.16, xwayland 24.1.6. Debian and Ubuntu ship backported fixes in package versions such as Debian bookworm 2:21.1.7-3+deb12u11 and Ubuntu noble 2:21.1.12-1ubuntu1.2. |
| Exposure reality | Narrow enterprise population: relevant mainly to Linux workstations, VDI, kiosks, lab machines, and remote-GUI/VNC estates — not typical headless servers or network edge devices. |
| Privilege context amplifier/reducer | The same bug swings from root LPE on rootful Xorg to user-session compromise on rootless Xorg/Xwayland. That runtime detail is the main reason this gets downgraded. |
| Disclosure and credit | Publicly disclosed 2025-02-25; ZDI credits Jan-Niklas Sohn and notes the vendor report date of 2024-11-15. |
noisgate verdict.
The decisive factor is attacker position: this bug starts only after a low-privileged foothold already exists on the target host. In many real deployments the vulnerable process is also not root anymore, so the practical blast radius is often a compromised user session or desktop node rather than a clean path to root across the fleet.
Why this verdict
- Down one full band for attacker position:
AV:L+PR:Lmeans the adversary already has code execution as a local user. That implies prior compromise and removes this from the 'stop the internet' category. - Down again for reachable population: X.Org/Xwayland is concentrated in Linux desktops, VDI, kiosks, dev workstations, and some VNC estates. For most 10,000-host enterprises, that is a much smaller slice than the total server fleet.
- Down for blast-radius uncertainty: modern Xorg can drop elevated rights automatically and Xwayland commonly runs in the user's session. When the target process is rootless, the exploit is still bad but no longer a universal root escalation.
- Not dropped further because impact can still be real: on legacy/rootful Xorg, VNC-backed desktops, or older workstation images, successful exploitation can yield root with no user interaction.
- No threat-intel amplifier: no KEV listing, no active exploitation evidence, and the supplied EPSS is extremely low.
Why not higher?
A higher rating would require either broader pre-auth reachability or real-world exploitation pressure. This CVE has neither: it is not a remote entry point, it is not KEV-listed, and its exploit chain begins only after a low-privileged foothold on the host already exists. Even the worst-case outcome depends on whether the target still runs a privileged X server.
Why not lower?
This is still memory corruption in a privileged or semi-privileged display component, not a theoretical edge case. Enterprises with Linux desktops, engineering workstations, kiosk images, shared lab systems, or rootful VNC/Xorg stacks can absolutely turn this into a meaningful local escalation path, so treating it as backlog-only hygiene would undercall the risk.
What to do — in priority order.
- Inventory GUI Linux assets — Identify where
Xorg,Xwayland, VNC, kiosk builds, and Linux VDI actually exist, and do it now so you can constrain the true exposure set. For a MEDIUM finding there is no mitigation SLA, but you should complete exposure mapping early and then drive patching inside the 365-day remediation window. - Prefer rootless Xorg — Confirm
Xorg.wrapis not forcingneeds_root_rights=yesunless there is a hardware/legacy requirement. This directly cuts the exploit payoff from root LPE to user-context compromise; validate and enforce during the next desktop engineering cycle, with patching still completed inside the 365-day remediation window. - Remove X11 stacks from servers — On server roles that do not need a local GUI, uninstall or avoid shipping X.Org/Xwayland packages entirely. That deletes the vulnerable code path rather than trying to shield it; because this is MEDIUM, there is no mitigation SLA, but cleanup should be folded into normal hardening and patch completion inside the 365-day remediation window.
- Constrain remote GUI services — Limit VNC/X11 forwarding/remote desktop access to jump hosts and admin groups, especially where Xorg may still run with elevated rights. This does not fix the bug, but it reduces who can reach the vulnerable server after obtaining a user foothold; implement in routine hardening while still meeting the 365-day remediation window.
- Watch for Xorg/Xwayland crashes and child processes — Add detections for abnormal
Xorg/Xwaylandrestarts, coredumps, and suspicious child processes spawned from display-server contexts. That helps you catch exploitation attempts on the smaller but higher-value GUI estate while patching proceeds within the 365-day remediation window.
- Perimeter controls like WAFs or internet-facing NGFW rules do not help; this is not a network-exposed bug.
- MFA does nothing once the attacker already has local code execution on the box.
- Relying on KEV absence is not a control; it only tells you CISA has not listed active exploitation evidence.
- Generic vulnerability scans alone are insufficient because they usually miss the key runtime question: is Xorg/Xwayland present and running with elevated rights?
Crowdsourced verification payload.
Run this on the target Linux host as a normal user; root is not required unless your package manager blocks local metadata reads. Save as check-cve-2025-26597.sh and execute with bash check-cve-2025-26597.sh. The script uses distro-aware package checks for Debian/Ubuntu where backports matter, and falls back to upstream binary versions elsewhere.
#!/usr/bin/env bash
# check-cve-2025-26597.sh
# Detect likely exposure to CVE-2025-26597 on Linux hosts.
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
status="UNKNOWN"
reason="Could not determine installed/fixed package versions"
have_cmd() { command -v "$1" >/dev/null 2>&1; }
version_ge() {
# usage: version_ge current fixed
if have_cmd dpkg; then
dpkg --compare-versions "$1" ge "$2"
return $?
fi
# rpm-ish / generic fallback using sort -V
[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | tail -n1)" = "$1" ]
}
get_os_id() {
if [ -r /etc/os-release ]; then
. /etc/os-release
echo "${ID:-unknown}:${VERSION_CODENAME:-${VERSION_ID:-unknown}}"
else
echo "unknown:unknown"
fi
}
check_debian_ubuntu() {
local os="$1"
local id="${os%%:*}"
local codename="${os#*:}"
local xorg_ver=""
local xwayland_ver=""
local xorg_fixed=""
local xwayland_fixed=""
local vulnerable=0
local unknown=0
if have_cmd dpkg-query; then
xorg_ver="$(dpkg-query -W -f='${Version}' xserver-xorg-core 2>/dev/null || true)"
xwayland_ver="$(dpkg-query -W -f='${Version}' xwayland 2>/dev/null || true)"
fi
case "$id:$codename" in
ubuntu:noble) xorg_fixed='2:21.1.12-1ubuntu1.2'; xwayland_fixed='2:23.2.6-1ubuntu0.4' ;;
ubuntu:jammy) xorg_fixed='2:21.1.4-2ubuntu1.7~22.04.13'; xwayland_fixed='2:22.1.1-1ubuntu0.17' ;;
ubuntu:focal) xorg_fixed='2:1.20.13-1ubuntu1~20.04.19'; xwayland_fixed='' ;;
ubuntu:oracular) xorg_fixed='2:21.1.13-2ubuntu1.2'; xwayland_fixed='2:24.1.2-1ubuntu0.4' ;;
ubuntu:plucky) xorg_fixed='2:21.1.16-1ubuntu1'; xwayland_fixed='2:24.1.5-1ubuntu1' ;;
debian:bookworm) xorg_fixed='2:21.1.7-3+deb12u11'; xwayland_fixed='' ;;
debian:bullseye) xorg_fixed='2:1.20.11-1+deb11u17'; xwayland_fixed='' ;;
debian:trixie) xorg_fixed='2:21.1.16-1.3+deb13u1'; xwayland_fixed='2:24.1.6-1' ;;
*) return 2 ;;
esac
if [ -n "$xorg_ver" ] && [ -n "$xorg_fixed" ]; then
if version_ge "$xorg_ver" "$xorg_fixed"; then
:
else
vulnerable=1
reason="xserver-xorg-core $xorg_ver is below fixed $xorg_fixed"
fi
elif [ -n "$xorg_fixed" ]; then
unknown=1
fi
if [ -n "$xwayland_fixed" ]; then
if [ -n "$xwayland_ver" ]; then
if version_ge "$xwayland_ver" "$xwayland_fixed"; then
:
else
vulnerable=1
reason="xwayland $xwayland_ver is below fixed $xwayland_fixed"
fi
else
unknown=1
fi
fi
if [ "$vulnerable" -eq 1 ]; then
status="VULNERABLE"
return 1
fi
if [ -n "$xorg_ver" ] || [ -n "$xwayland_ver" ]; then
status="PATCHED"
reason="Installed Debian/Ubuntu package versions meet known fixed thresholds"
return 0
fi
if [ "$unknown" -eq 1 ]; then
status="UNKNOWN"
reason="Expected package names not installed or not queryable"
return 2
fi
return 2
}
extract_upstream_ver() {
# Pull first semantic-looking version from stdin
grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n1
}
check_upstream_fallback() {
local xorg_up=""
local xwayland_up=""
local xorg_vuln=0
local xwayland_vuln=0
local found=0
if have_cmd Xorg; then
xorg_up="$(Xorg -version 2>&1 | extract_upstream_ver || true)"
if [ -n "$xorg_up" ]; then
found=1
if version_ge "$xorg_up" '21.1.16'; then
:
else
xorg_vuln=1
reason="Xorg upstream version $xorg_up is below 21.1.16"
fi
fi
fi
if have_cmd Xwayland; then
xwayland_up="$(Xwayland -version 2>&1 | extract_upstream_ver || true)"
if [ -n "$xwayland_up" ]; then
found=1
if version_ge "$xwayland_up" '24.1.6'; then
:
else
xwayland_vuln=1
reason="Xwayland upstream version $xwayland_up is below 24.1.6"
fi
fi
fi
if [ "$found" -eq 0 ]; then
status="UNKNOWN"
reason="Neither Xorg nor Xwayland binaries were found"
return 2
fi
if [ "$xorg_vuln" -eq 1 ] || [ "$xwayland_vuln" -eq 1 ]; then
status="VULNERABLE"
return 1
fi
status="PATCHED"
reason="Installed upstream binary versions meet fixed thresholds"
return 0
}
main() {
local os
os="$(get_os_id)"
if check_debian_ubuntu "$os"; then
echo "$status - $reason"
exit 0
else
rc=$?
if [ "$rc" -eq 1 ]; then
echo "$status - $reason"
exit 1
fi
fi
check_upstream_fallback
rc=$?
echo "$status - $reason"
exit "$rc"
}
main
If you remember one thing.
Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.