This is a valet ticket swap that lets a low-priv user walk away with the root keys
CVE-2026-41651 is a local privilege escalation in packagekitd, the root-running D-Bus service behind PackageKit. A low-privileged local user can queue an allowed transaction, then overwrite its flags and payload before execution so the daemon installs attacker-controlled packages as root; package scriptlets then deliver full root execution. Upstream says versions >= 1.0.2 and <= 1.3.4 are confirmed vulnerable, with likely exposure back to 0.8.1; the upstream fix is 1.3.5, and major distros shipped backports.
The vendor's HIGH 8.8 is technically fair, but operationally this is not a CRITICAL fire drill because it requires an existing local foothold (AV:L/PR:L). That prerequisite matters: on a 10,000-host estate this is a post-initial-access privilege escalator, not an entry vector. What keeps it in HIGH instead of dropping further is that exploitation is reliable, fast, publicly weaponized, and root-complete on default installs across multiple distros.
5 steps from start to impact.
Land a low-priv shell
- Attacker has local code execution or a valid low-priv account
- Target is Linux with PackageKit installed
- No remote unauthenticated path into
packagekitd - This assumes the attacker already beat your initial-access controls
Reach PackageKit over system D-Bus
packagekitd over the system bus, typically with D-Bus client calls that mirror InstallFiles() behavior. Because PackageKit can be D-Bus activated, the daemon may not appear persistently in a process list even when exploitable. Weaponized tooling: public PoCs such as Vozec/CVE-2026-41651 or custom gdbus/libdbus clients.- PackageKit is installed
- System D-Bus service is available
- Policy allows the initial 'safe' transaction path
- Some servers do not install PackageKit at all
- Minimal images and hardened server builds often remove PackageKit/Cockpit integration
packagekit packages and whether packagekit.service is loaded or D-Bus activatable.Queue a 'safe' transaction
InstallFiles() call with flags such as SIMULATE, which PackageKit treats as non-destructive and therefore skips polkit authorization for. This moves the transaction into a state that will later be executed by the scheduler. Weaponized step: the PoC's first async D-Bus call.- Vulnerable PackageKit transaction handling
- Attacker can submit D-Bus method calls as an unprivileged user
- If PackageKit package-install actions are denied outright by local polkit policy, this chain breaks early
- Hosts without PackageKit package installation features exposed are not affected
Overwrite flags before dispatch
InstallFiles() call on the same transaction with real install flags and an attacker-controlled package path. The bug chain matters here: PackageKit overwrites cached flags unconditionally, silently rejects the backward state transition, and later reads the overwritten flags at execution time. Telekom's write-up notes GLib main-loop ordering makes this deterministic rather than a flaky race. Weaponized step: the PoC's second async D-Bus call.- Same transaction can be reused before idle callback execution
- Daemon is running an unpatched transaction state machine
- Patched versions or distro backports remove the overwrite path
- Aggressive host hardening that disables PackageKit package installs for non-root users blocks abuse
Run package scriptlets as root
postinst/RPM scriptlet executes arbitrary commands to drop a SUID shell, add sudoers entries, or implant persistence. At that point the attacker owns the box. Weaponized tooling: crafted .deb/.rpm payload package from public PoCs.- Attacker can place a malicious package file locally
- Backend install path is reached before polkit denial matters
- Some MAC policies or filesystem controls may block the post-exploitation payload choice
- This is single-host privilege escalation, not domain-wide by itself
journalctl -u packagekit for assertion failures like the emitted_finished crash pattern, plus package install history and sudden SUID file creation.The supporting signals.
| In-the-wild status | No confirmed KEV listing and no authoritative public in-the-wild campaign evidence found as of 2026-05-31. This is an inference from current public sources plus the user's intel block, not a claim of absence forever. |
|---|---|
| PoC availability | Public exploit code exists. Telekom's timeline says a GitHub exploit appeared on 2026-04-23, and live repos such as Vozec/CVE-2026-41651 show working weaponization. |
| EPSS | 0.00153 from the user's intel block. That's low, which fits a non-remote LPE, but EPSS routinely underweights post-compromise privilege escalators that operators use after access is already gained. |
| KEV status | Not KEV-listed per the user's intel block; no corresponding entry was found in CISA's current KEV catalog view. |
| CVSS vector reality check | CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H correctly says easy local root. The operational downgrade pressure is entirely in AV:L/PR:L: attacker must already be on the box. |
| Affected versions | Upstream GHSA says affected >= 0.8.1 and <= 1.3.4, with confirmed vulnerable >= 1.0.2 and <= 1.3.4. Tested by the vendor researchers on Ubuntu, Debian, Rocky Linux, and Fedora default installs. |
| Fixed versions | Upstream fixed in 1.3.5. Notable distro backports: Debian bullseye 1.2.2-2+deb11u1, bookworm 1.2.6-5+deb12u1, trixie 1.3.1-1+deb13u1; Ubuntu noble 1.2.8-2ubuntu1.5, jammy 1.2.5-2ubuntu3.1, focal 1.1.13-2ubuntu1.1+esm1; Fedora 42-44 1.3.4-3 per Telekom. |
| Exposure and scanning | No meaningful Shodan/Censys-style internet exposure signal. packagekitd is a local D-Bus service, often D-Bus activated, so external attack-surface tools will undercount or miss it entirely. The real exposure question is where PackageKit is installed, especially desktops and Cockpit-enabled servers. |
| Disclosure timeline | Public disclosure and upstream fix landed on 2026-04-22. Telekom's timeline says private report 2026-04-08, distros notified by 2026-04-19, and public GitHub exploit available 2026-04-23. |
| Reporter / research org | Reported by Deutsche Telekom Red Team; GHSA credits reporter msatdt and remediation developer ximion. |
noisgate verdict.
The single biggest factor is attacker position: this flaw requires an already-established local low-privileged foothold, which makes it a post-compromise escalator, not an initial-access event. It stays HIGH because once that foothold exists, the exploit path is reliable, publicly available, and ends in immediate full-root compromise on the host.
Why this verdict
- Local authenticated foothold required — score down from 8.8.
AV:L/PR:Lmeans the attacker must already have shell/code execution or a valid unprivileged account on the host, so this is not a perimeter-breaking bug. - Exploit reliability and public weaponization — score back up. Telekom describes the GLib event ordering that makes the race dependable, and public GitHub PoCs remove most engineering work for post-compromise operators.
- Wide install base, but not universal and not internet-facing. PackageKit is common on desktops and present on some servers via Cockpit, yet plenty of hardened or minimal server images do not ship it, which trims the reachable population.
Why not higher?
This is not higher because there is no unauthenticated remote path and no credible public evidence that it is being broadly exploited in the wild right now. The exploit chain begins only after another control has already failed and the attacker is executing locally as a normal user.
Why not lower?
This is not lower because the impact is full root, the exploit is fast and deterministic, and tested-default-install coverage spans multiple mainstream distros. For shared Linux systems, developer workstations, VDI, jump hosts, and Cockpit-managed servers, this is exactly the kind of LPE operators use to turn a nuisance foothold into a real incident.
What to do — in priority order.
- Patch PackageKit or deploy distro backports — Make the package update the primary control and complete it within 180 days for the HIGH verdict, faster on multi-user Linux systems. Where patch rollout is lagging, use the distro-provided backport rather than waiting for upstream
1.3.5exactly. - Deny PackageKit install actions for non-root users — If you cannot patch promptly, deploy the vendor-recommended
polkitrule to block PackageKit package-install actions for non-root users within 30 days. This directly cuts the exploit chain at the authorization boundary and is the best compensating control for exposed-but-unpatched hosts. - Remove or mask PackageKit on servers that do not need it — On server roles where GUI software management is irrelevant, uninstall PackageKit or mask/disable the service path within 30 days. This shrinks your reachable population and is especially useful on Cockpit-enabled or admin utility images.
- Hunt for PackageKit assertion crashes — Search
journalctl -u packagekitand central log stores for the PackageKit assertion-failure IOC described by Telekom within 30 days and keep the detection in place until remediation is complete. Successful exploitation tends to leave a noisy daemon crash trail even though systemd recovers the service. - Prioritize user-accessible Linux hosts — Sequence your estate so shared desktops, dev workstations, bastions, teaching/research clusters, and any host where non-admin users can run code get attention first within 30 days. The business risk is highest where many low-privileged users can touch the box.
- A WAF or perimeter IPS does nothing here because the vulnerable path is local D-Bus traffic, not an exposed HTTP service.
- Checking only the running process list is weak coverage because PackageKit may be D-Bus activated and absent until invoked.
- MFA helps protect initial access but does not stop abuse once an attacker already has a local user context on the host.
- Hardening
sudoalone does not help because the exploit bypasses normal admin elevation flow and runs package scriptlets as root through PackageKit.
Crowdsourced verification payload.
Run this on the target Linux host, not from a remote scanner. Invoke it as bash ./check-packagekit-cve-2026-41651.sh; no root is strictly required for package-version checks, but root helps if you also want to validate service status and logs. The script prints VULNERABLE, PATCHED, or UNKNOWN and exits 0, 1, or 2 respectively.
#!/usr/bin/env bash
# check-packagekit-cve-2026-41651.sh
# Detect likely exposure to CVE-2026-41651 on Debian/Ubuntu/RPM-based Linux hosts.
# Exit codes: 0=PATCHED/NOT INSTALLED, 1=VULNERABLE, 2=UNKNOWN
set -u
CVE="CVE-2026-41651"
OS_ID="unknown"
OS_VER="unknown"
INSTALLED_VER=""
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
OS_ID="${ID:-unknown}"
OS_VER="${VERSION_ID:-unknown}"
fi
say() { echo "$1"; }
fail_unknown() { say "UNKNOWN: $1"; exit 2; }
fail_vuln() { say "VULNERABLE: $1"; exit 1; }
pass_patch() { say "PATCHED: $1"; exit 0; }
check_dpkg() {
if ! command -v dpkg-query >/dev/null 2>&1; then
return 1
fi
if ! dpkg-query -W -f='${Status} ${Version}\n' packagekit 2>/dev/null | grep -q '^install ok installed '; then
pass_patch "packagekit not installed"
fi
INSTALLED_VER="$(dpkg-query -W -f='${Version}' packagekit 2>/dev/null)"
[[ -n "$INSTALLED_VER" ]] || fail_unknown "packagekit installed but version could not be read"
FIXED=""
case "$OS_ID:$OS_VER" in
ubuntu:24.04) FIXED='1.2.8-2ubuntu1.5' ;;
ubuntu:22.04) FIXED='1.2.5-2ubuntu3.1' ;;
ubuntu:20.04) FIXED='1.1.13-2ubuntu1.1+esm1' ;;
ubuntu:18.04) FIXED='1.1.9-1ubuntu2.18.04.6+esm1' ;;
ubuntu:16.04) FIXED='0.8.17-4ubuntu6~gcc5.4ubuntu1.5+esm1' ;;
debian:11) FIXED='1.2.2-2+deb11u1' ;;
debian:12) FIXED='1.2.6-5+deb12u1' ;;
debian:13) FIXED='1.3.1-1+deb13u1' ;;
esac
if [[ -n "$FIXED" ]]; then
if dpkg --compare-versions "$INSTALLED_VER" ge "$FIXED"; then
pass_patch "packagekit $INSTALLED_VER on $OS_ID $OS_VER is at or above fixed distro version $FIXED"
else
fail_vuln "packagekit $INSTALLED_VER on $OS_ID $OS_VER is below fixed distro version $FIXED"
fi
fi
if dpkg --compare-versions "$INSTALLED_VER" ge '1.3.5'; then
pass_patch "packagekit $INSTALLED_VER is at or above upstream fixed version 1.3.5"
fi
if dpkg --compare-versions "$INSTALLED_VER" ge '1.0.2' && dpkg --compare-versions "$INSTALLED_VER" le '1.3.4'; then
fail_vuln "packagekit $INSTALLED_VER falls in confirmed vulnerable upstream range 1.0.2-1.3.4"
fi
fail_unknown "packagekit $INSTALLED_VER could not be mapped confidently to a fixed or vulnerable state"
}
check_rpm() {
if ! command -v rpm >/dev/null 2>&1; then
return 1
fi
if ! rpm -q PackageKit >/dev/null 2>&1; then
pass_patch "PackageKit not installed"
fi
INSTALLED_VER="$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' PackageKit 2>/dev/null)"
[[ -n "$INSTALLED_VER" ]] || fail_unknown "PackageKit installed but version could not be read"
ver_ge() {
local a="$1" b="$2"
[[ "$(printf '%s\n%s\n' "$a" "$b" | sort -V | tail -n1)" == "$a" ]]
}
ver_le() {
local a="$1" b="$2"
[[ "$(printf '%s\n%s\n' "$a" "$b" | sort -V | head -n1)" == "$a" ]]
}
case "$OS_ID" in
fedora)
if ver_ge "$INSTALLED_VER" '1.3.4-3'; then
pass_patch "PackageKit $INSTALLED_VER on Fedora is at or above known fixed build 1.3.4-3"
fi
;;
rhel|rocky|almalinux|centos)
if [[ "$OS_VER" == 9* ]] && ver_ge "$INSTALLED_VER" '1.2.6-1.el9_4.1'; then
pass_patch "PackageKit $INSTALLED_VER on EL9 is at or above known fixed build 1.2.6-1.el9_4.1"
fi
;;
esac
if ver_ge "$INSTALLED_VER" '1.3.5'; then
pass_patch "PackageKit $INSTALLED_VER is at or above upstream fixed version 1.3.5"
fi
if ver_ge "$INSTALLED_VER" '1.0.2' && ver_le "$INSTALLED_VER" '1.3.4'; then
fail_vuln "PackageKit $INSTALLED_VER falls in confirmed vulnerable upstream range 1.0.2-1.3.4"
fi
fail_unknown "PackageKit $INSTALLED_VER could not be mapped confidently to a fixed or vulnerable RPM build"
}
check_dpkg || true
check_rpm || true
fail_unknown "unsupported package manager or unable to determine PackageKit installation state for $CVE"If you remember one thing.
polkit deny rule or remove/disable PackageKit where it is unnecessary. The noisgate remediation SLA is within 180 days: roll the actual distro patch/backport across the fleet, but do the user-accessible Linux population first because this bug turns any ordinary foothold into root with very little drama.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.