CVE-2026-41651 — PackageKit TOCTOU Local Privilege Escalation
Classification: Purple Team Assessment Artifact
Authorized use only. This document and the accompanying test script are intended solely for internal security validation on systems where written authorization has been obtained.
Proof of Exploitation

Table of Contents
- Vulnerability Overview
- Technical Analysis
- Test Script Description
- Indicators of Compromise
- Detection Logic
- Affected Systems & Versions
- Remediation
- References
Vulnerability Overview
PackageKit is a D-Bus abstraction layer for system package management, present by default on GNOME-based desktops across Debian, Ubuntu, Fedora, RHEL, SUSE, and Arch Linux. Because it mediates privileged package operations on behalf of unprivileged users, a flaw in its authorization flow has system-wide root impact.
Technical Analysis
Root Cause
pk-transaction.c (pre-1.3.5) did not enforce a state guard on action method re-invocation. A D-Bus client could call InstallFiles (or other action methods) multiple times on the same transaction object after it had already transitioned out of PK_TRANSACTION_STATE_NEW.
Attack Chain
Attacker (unprivileged)
│
├─① CreateTransaction() → PackageKit returns transaction object path (tid)
│
├─② InstallFiles(tid, FLAG_SIMULATE=4, [dummy.pkg])
│ PackageKit queues a polkit authorization check for dummy.pkg.
│ No installation occurs yet — SIMULATE means dry-run only.
│
├─③ InstallFiles(tid, FLAG_NONE=0, [payload.pkg]) ← TOCTOU window
│ Re-invokes on the same tid before auth resolves.
│ Vulnerable versions overwrite the queued parameters with payload.pkg.
│
└─④ polkit grants authorization (user approved or auto-authorized)
packagekitd installs payload.pkg as root.
payload postinst/post script: install -m 4755 /bin/bash /tmp/.suid_bash
Attacker executes /tmp/.suid_bash -p → root shell.
Why the Race Wins
Steps ② and ③ are sent as non-blocking async D-Bus calls on the same connection and flushed in a single write. The two messages arrive at packagekitd before it can process ② and advance the state machine, leaving the TOCTOU window open. The fix in 1.3.5 adds an explicit state check that returns PK_TRANSACTION_ERROR_INVALID_STATE on any re-invocation after PK_TRANSACTION_STATE_NEW.
Test Script Description
File: cve-2026-41651-purpleteam.py
Language: Python 3
Dependencies: python3-gi (GObject introspection / GLib/Gio bindings)
Purpose
Demonstrates exploitability of CVE-2026-41651 on a prepared test system for the purposes of:
- Validating whether the installed PackageKit version is vulnerable
- Generating realistic IOC telemetry for SIEM/EDR tuning
- Testing detection coverage before and after patching
Behavior
Hardened Environment Support
Default-hardened systems can block the exploit at two independent points. The script handles both automatically.
1. Restrictive umask (027 / 077)
A process-inherited umask of 027 or 077 causes mkdir() to produce 750 or 700 directories. Both dpkg-deb and rpmbuild must traverse the full build tree — if any directory is unreadable the build fails silently.
Fix applied: os.umask(0o022) is called at startup before any file or directory is created. Additionally, every directory and file in the build tree receives an explicit chmod immediately after creation (0o755 for directories and scripts, 0o644 for data files), so the correct permissions are guaranteed regardless of the inherited umask.
2. nosuid / noexec mount flags on /tmp
| Flag | Effect on exploit |
|---|
nosuid | Kernel silently strips the SUID bit from any file stored on that filesystem — the copied bash never becomes root |
noexec | The SUID binary cannot be executed at all |
Fix applied: At startup, _find_suid_dir() reads /proc/mounts and tests candidate directories in preference order until it finds one whose filesystem has neither flag set. The resolved path is then baked into the payload's post-install script and used for polling and execution.
If all candidates are blocked the script exits with a clear error rather than silently failing.
Compatibility
| Distribution Family | Package Tool | Tested |
|---|
| Debian / Ubuntu | dpkg-deb | ✓ |
| RHEL / Fedora |
Indicators of Compromise
IOCs are listed from generic/infrastructure-level down to script-specific artifacts. Detections built on the generic indicators will catch this CVE regardless of which PoC variant is used.
File System
Process & Execution
D-Bus Activity
Audit Log Patterns
Enable with: auditctl -a always,exit -F arch=b64 -S all -F path=/usr/bin/packagekitd
Or use the rules below in /etc/audit/rules.d/:
# Detect SUID file creation in all candidate drop directories
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/tmp -k suid_drop
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/var/tmp -k suid_drop
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F a2&04000 -F dir=/dev/shm -k suid_drop
# Detect dpkg-deb / rpmbuild by non-root
-w /usr/bin/dpkg-deb -p x -k pkg_build_nonroot
-w /usr/bin/rpmbuild -p x -k pkg_build_nonroot
# Detect SUID bash execution from any candidate drop directory
-a always,exit -F arch=b64 -S execve -F dir=/tmp -F uid!=0 -F euid=0 -k priv_esc_drop
-a always,exit -F arch=b64 -S execve -F dir=/var/tmp -F uid!=0 -F euid=0 -k priv_esc_drop
-a always,exit -F arch=b64 -S execve -F dir=/dev/shm -F uid!=0 -F euid=0 -k priv_esc_drop
Package Manager Artifacts
Privilege Escalation Artifacts
Detection Logic
SIEM Pseudo-Rule (Generic — covers all CVE-2026-41651 variants)
(
event.category == "process"
AND process.name IN ("dpkg-deb", "rpmbuild")
AND process.user.id != "0"
AND NOT process.parent.name IN ("apt", "apt-get", "dpkg", "rpm", "dnf", "yum", "zypper", "mock", "koji")
)
OR
(
event.category == "file"
AND file.path LIKE "/tmp/%" OR file.path LIKE "/var/tmp/%" OR file.path LIKE "/dev/shm/%"
AND file.owner == "root"
AND (file.mode LIKE "04%")
)
OR
(
event.category == "process"
AND process.name == "bash"
AND process.real_user.id != "0"
AND process.effective_user.id == "0"
AND NOT process.parent.name IN ("sudo", "su", "sshd", "login", "pam")
)
EDR Behavioral Chain
packagekitd
└─ sh / bash (cwd or arg matches /tmp, /var/tmp, /dev/shm, or $HOME)
└─ install / cp / chmod (target has SUID + owner root)
Flag the full chain. Any individual step alone may be benign; the parent-child relationship through packagekitd to a SUID-setting command is high-fidelity regardless of which drop directory was selected. Widen path-based rules to cover all four candidates.
Affected Systems & Versions
Check installed version: pkcon backend-details or packagekit --version
Vulnerable if reported version is ≤ 1.3.4.
Primary: Upgrade PackageKit to 1.3.5 or apply the vendor-specific backport.
# Debian / Ubuntu
apt update && apt install --only-upgrade packagekit
# Fedora / RHEL
dnf upgrade packagekit
# SUSE
zypper update packagekit
Mitigations (if patching is not immediately possible):
References
Generated: 2026-04-24 | Updated: 2026-04-25 | Purple Team Assessment | Internal Use Only