Most Linux privilege reviews stop at sudoers, but polkit is a second, parallel path to root-level actions that decides who can manage services, mount disks, change networking, install packages or run pkexec, and it is rarely reviewed. polkit (formerly PolicyKit) is the authorisation framework that privileged D-Bus services consult before acting for an unprivileged caller. Its defaults differ by distribution and by whether a user is sitting at the console, which is why flaws such as PwnKit (CVE-2021-4034) and CVE-2021-3560 turned it into a common escalation route. This guide explains how polkit decides, which files and rules matter, how pkexec fits in, how to log and detect misuse, and how to harden servers and desktops. It is for Linux administrators, platform engineers and security reviewers. It goes deeper than the Linux Privilege Escalation Techniques Guide and complements the sudo and sudoers Security Guide.
Key takeaways
- polkit is a second sudoers. Every action a D-Bus mechanism defines (systemd units, logins, disks, networking, accounts, packages) has its own authorisation, separate from sudo, and should be in scope for privilege reviews.
- "Active" is an authorisation input. Defaults distinguish allow_active (local console session), allow_inactive and allow_any (for example SSH); anything that makes a remote user look active, as CVE-2025-6018 did, unlocks desktop-grade privileges.
- Rules are JavaScript that runs first match wins. Files in /etc/polkit-1/rules.d and the other rules directories are processed in lexical order, and an early rule that returns a value can silently override everything after it.
- pkexec is a setuid root binary. PwnKit showed that its presence alone was enough for local root on most distributions; remove it from servers that do not need it, and patch fast.
- Prefer auth_admin, avoid _keep with variables. Upstream documentation says auth_self is not restrictive enough on multi-user systems, and *_KEEP results cache authorisation for about five minutes even if the request details change.
How identity and access work in polkit
polkit separates three parties. A mechanism is a privileged service, usually on the system D-Bus, such as systemd, logind, udisks or NetworkManager. A subject is the unprivileged process asking it to do something. The authority is polkitd, which provides the org.freedesktop.PolicyKit1 service and runs as the unprivileged polkitd system user. The mechanism asks the authority whether the subject is authorised for a named action and acts on the answer.
Where the decision comes from
- Action declarations: XML
.policyfiles in/usr/share/polkit-1/actionsdefine action IDs (for exampleorg.freedesktop.login1.reboot) and their implicit defaults. List them withpkaction; view one withpkaction -v --action-id=<id>. - Authorisation rules: JavaScript
.rulesfiles read from/etc/polkit-1/rules.d,/run/polkit-1/rules.d,/usr/local/share/polkit-1/rules.dand/usr/share/polkit-1/rules.d. Files are ordered by basename across all directories; on a tie, the earlier directory wins. All directories are monitored and reloaded when a file changes. - Distribution layers: SUSE applies its own profiles (easy, standard, restrictive) over upstream defaults, selected with
POLKIT_DEFAULT_PRIVSin/etc/sysconfig/securityand applied withset_polkit_default_privs, with local overrides in/etc/polkit-default-privs.local. On SUSE,pkactionshows upstream defaults only, so it can mislead a review.
Implicit authorisations
| Context | Applies to | Security note |
|---|---|---|
| allow_active | Clients in the active session on a local console | Most generous on desktops; must never be reachable remotely |
| allow_inactive | Clients in inactive local console sessions | Usually stricter than active |
| allow_any | Any other client, including SSH and service processes | The setting that matters most on servers |
| Value | Meaning | Use |
|---|---|---|
| no | Not authorised | Default for sensitive actions on servers |
| yes | Authorised without authentication | Only for harmless actions or tightly scoped rules |
| auth_self / auth_self_keep | Session owner must authenticate as themselves | Upstream warns it is not restrictive enough on multi-user systems |
| auth_admin / auth_admin_keep | An administrative identity must authenticate | Recommended baseline for privileged actions |
The _keep variants retain the authorisation for a short period, 300 seconds by default (ExpirationSeconds in polkitd.conf). Authentication itself is performed by an authentication agent in the user's session, or by pkttyagent for text sessions, with polkit-agent-helper-1 verifying credentials through PAM. See the Linux PAM Guide.
Admin roles and privileged access
"Administrator" in polkit is whatever addAdminRule() returns: an array of identities such as unix-group:wheel, unix-netgroup:<netgroup> or unix-user:<user>. Distributions ship a default admin rule; Red Hat family systems commonly use the wheel group and Debian family systems the sudo group. Membership of that group therefore grants two things: sudo rights and the ability to satisfy every auth_admin prompt.
- Review the admin group as privileged: include wheel or sudo membership, and every
addAdminRulein rules files, in privileged access reviews. See the Unix and Linux Privileged Access Guide. - pkexec: runs a program as another user, root by default. The default action
org.freedesktop.policykit.execrequires administrator authentication, and pkexec sets a minimal environment andPKEXEC_UID. It does not validate arguments, so any custom action (via theorg.freedesktop.policykit.exec.pathannotation) that lets users run a program without fresh admin authentication must treat input as untrusted, like any setuid program. - Remove pkexec where unused: servers rarely need it. Qualys' PwnKit advisory notes the vulnerable code dated from May 2009, that exploitation did not need polkitd to be running, and gave removing the setuid bit (
chmod 0755 /usr/bin/pkexec) as a stopgap until patching. - Delegate narrowly: if an operations group needs to restart one service, write a rule for that action and unit, rather than adding them to wheel.
Writing safe delegation rules
Rules receive an action (with id and lookup() for mechanism variables) and a subject (with user, groups, isInGroup(), local, active, system_unit and no_new_privileges). A rule that grants one group the right to manage one systemd unit, and nothing else, looks like this:
// /etc/polkit-1/rules.d/50-ops-restart-app.rules
polkit.addRule(function(action, subject) {
if (action.id == "org.freedesktop.systemd1.manage-units" &&
action.lookup("unit") == "app.service" &&
subject.isInGroup("app-ops")) {
return polkit.Result.AUTH_ADMIN;
}
});
- Match exact IDs: prefix matches such as
indexOf("org.freedesktop.udisks2.") == 0grant every current and future action in the namespace. - Do not trust display strings: pkexec's
command_linevariable is documented as not secure for checks; useprogram. - Avoid _KEEP when the rule depends on variables: a cached YES applies to the same action and subject even if the variables differ.
- Use spawn() sparingly: helpers run as the polkitd user, block other checks while running and are killed after 10 seconds; rules running longer than 15 seconds are killed.
- Name files deliberately: a rule that must run first goes in
/etc/polkit-1/rules.dwith a low prefix such as00-; use two-digit prefixes throughout so ordering is visible.
Integrations, API tokens and service accounts
polkit is not only for humans at a desktop. Service accounts, agents and automation call D-Bus mechanisms too, and these non-human callers fall under allow_any.
- Bind automation to its unit: the
system_unitsubject attribute identifies the systemd system unit of the caller, andno_new_privilegesconfirms the unit hasNoNewPrivileges=set. Upstream's example allows user administration only for processes inadmin.servicethat cannot gain new privileges. System units need root to create, unlike user units, so this binding is meaningful. - Prefer unit identity over user name: a rule keyed on a service account's user name applies to any process running as that user, including an interactive shell an attacker obtains with its credentials. See the Linux Service Accounts and Keytab Management Guide.
- Configuration management: Ansible, Puppet or similar tools that deploy rules files hold the power to rewrite authorisation. Protect their credentials and review rule changes like sudoers changes.
- Query delegation: by default only root can ask whether a different user's process is authorised; the
org.freedesktop.policykit.ownerannotation lets a named system user do so, for daemons that run as non-root. - Meta actions: the
org.freedesktop.policykit.implyannotation authorises a list of other actions together. Review implied action lists when granting an umbrella action.
Logging and detection
polkitd logs to the system journal, and polkit.log() in rules writes with LOG_AUTHPRIV, which usually lands in /var/log/secure or the auth log. Collect both centrally. See the Linux Logging and auditd for Defenders Guide.
| Signal | Source | Why it matters | ATT&CK |
|---|---|---|---|
Execution of /usr/bin/pkexec, especially with an empty or unusual argument list or from a web or service account | auditd execve watch on pkexec; EDR process events | PwnKit-style exploitation and abuse | T1068, T1548.001 |
| Writes to rules or action directories | auditd file watches on /etc/polkit-1/, /usr/share/polkit-1/, /run/polkit-1/; file integrity monitoring | New rule granting YES is a quiet persistence path | T1548 |
| Temporary authorisations granted to unexpected users | polkitd journal entries | Shows who satisfied auth prompts and for which action | T1548 |
| Service management actions from non-admin users | systemd and logind journal, polkit authorisation logs | Delegated units used outside intent | T1543.002 |
| Changes to wheel or sudo group membership | auditd on /etc/group; directory logs | Expands who counts as admin | T1098 |
| Remote sessions marked active | loginctl session data, logind journal | allow_active privileges reachable over SSH (CVE-2025-6018 pattern) | T1068 |
Metrics
- pkexec presence: share of servers where pkexec is removed or not setuid. Target 100% of servers without a documented need.
- Patch latency: days from a polkit, udisks or related advisory to full deployment. CVE-2021-4034 is in the CISA Known Exploited Vulnerabilities catalogue with known ransomware use, so treat polkit fixes as urgent.
- Custom rule inventory: number of rules files outside vendor packages, each with an owner and review date.
- Unauthenticated grants: count of rules or overrides returning YES for privileged action namespaces. Target zero on servers.
- Admin identity count: users who satisfy auth_admin per host class, reviewed with sudoers.
Hardening baseline
Servers and desktops differ
| Area | Server baseline | Desktop baseline |
|---|---|---|
| pkexec | Remove the package or the setuid bit unless required | Keep patched; default auth_admin |
| allow_any for privileged actions | no or auth_admin | auth_admin |
| allow_active | Largely irrelevant if no local console users; confirm SSH sessions are never active | Convenient defaults acceptable for the single local user; avoid on shared machines |
| Disk, network and package mechanisms (udisks, NetworkManager, PackageKit) | Remove the services if unused | Restrict to the local active user |
| SUSE profile | restrictive | standard (easy only for single-user machines where the user is the administrator) |
| Custom rules | Delegation bound to system units and specific actions | Few or none |
Rollout
- Inventory: run
pkactionto list actions, list all.rulesfiles in the four rules directories with their package ownership, and record admin rule identities and pkexec setuid status per host. - Patch: confirm polkit, udisks and libblockdev packages include fixes for CVE-2021-4034, CVE-2021-3560 and CVE-2025-6019, and on SUSE 15 the PAM fix for CVE-2025-6018. Set
user_readenv=0forpam_env, the default from Linux-PAM 1.4.0. - Reduce: remove pkexec setuid and unused mechanisms on a pilot ring of servers; watch for broken automation for two weeks.
- Tighten: add a low-numbered rule that logs (with
polkit.log()) and returns AUTH_ADMIN for sensitive namespaces on servers, test withpkcheckand real workflows, then switch to NO where nothing breaks. - Monitor: deploy auditd watches on rules directories and pkexec, and forward polkitd and authpriv logs to the SIEM.
- Roll back: rules are files; removing or renaming the new
.rulesfile takes effect immediately because polkitd watches the directories. Restore pkexec permissions from the package (rpm --setpermsor reinstalling) if a dependency appears. On SUSE, restore defaults by selecting the profile, clearing.localoverrides and rerunningset_polkit_default_privs.
Framework mapping
| Control | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 | CIS Controls v8.1 | ISO/IEC 27001:2022 |
|---|---|---|---|---|
| Restrictive defaults, narrow delegation | AC-6, AC-6(1) | PR.AA-05 | 5, 6 | A.8.2 |
| Remove pkexec and unused mechanisms | CM-7, CM-7(5) | PR.PS-01 | 4 | A.8.9 |
| Patch polkit and related services | SI-2 | PR.PS-02 | 7 | A.8.8 |
| Protect rules files | CM-5, SI-7 | PR.PS-01 | 4 | A.8.9 |
| Log privileged actions | AU-2, AC-6(9) | DE.CM-09 | 8 | A.8.15 |
In MITRE ATT&CK v20, polkit abuse maps mainly to T1548 Abuse Elevation Control Mechanism, T1548.001 Setuid and Setgid for pkexec, and T1068 Exploitation for Privilege Escalation for flaws such as CVE-2021-4034 and CVE-2021-3560.
Common misconfigurations
- Unpatched pkexec on servers: PwnKit gave any local user root on default installs of major distributions; web shells and compromised service accounts are local users. Red Hat rated it CVSS 7.8 and published a SystemTap workaround for systems that could not update at once.
- Trusting identity lookups blindly: CVE-2021-3560 came from polkit treating a failed D-Bus UID lookup as UID 0, affecting polkit 0.113 and later until the June 2021 fix. Old base images still carry it.
- Remote users treated as local: on openSUSE Leap 15 and SUSE Linux Enterprise 15, CVE-2025-6018 let an SSH user be treated as allow_active through
~/.pam_environment, opening desktop privileges such as udisks operations used in CVE-2025-6019. - Catch-all rules: a rule returning YES for any action when the user is in an admin-like group, often added to "stop the password prompts", turns group membership into silent root.
- Editing vendor policy files: changes to
/usr/share/polkit-1/actionsare overwritten by updates and hide intent; SUSE explicitly advises writing your own policy and rules instead. - Reviewing sudoers only: privileged access reviews that ignore polkit admin rules and custom rules miss a full second path to root-level actions.
Practitioner checklist
- polkit, udisks, libblockdev and PAM packages are patched for CVE-2021-4034, CVE-2021-3560, CVE-2025-6018 and CVE-2025-6019 where applicable.
- pkexec is removed or not setuid on servers that do not need it.
- Every custom
.rulesfile is in configuration management, owned, reviewed and named with a two-digit prefix. - No rule returns YES for systemd, login, udisks, NetworkManager, accounts or PackageKit namespaces on servers without an exact action and unit match.
- Admin identities from
addAdminRuleand the wheel or sudo group are included in privileged access reviews. - Delegation to automation uses
system_unitandno_new_privilegesrather than user names. - SSH sessions are confirmed never to be marked active;
pam_envhasuser_readenv=0. - auditd watches cover pkexec execution and writes to polkit rules and action directories, with logs in the SIEM.
- SUSE hosts use the restrictive profile on servers and keep overrides in
/etc/polkit-default-privs.local.
Standards and references
- polkit project: polkit(8) Authorization Manager
- polkit project: pkexec(1)
- SUSE: The Polkit authentication framework
- Qualys: PwnKit, local privilege escalation in polkit's pkexec (CVE-2021-4034)
- GitHub Security Lab: Privilege escalation with polkit (CVE-2021-3560)
- Qualys: Local privilege escalation via PAM and udisks (CVE-2025-6018, CVE-2025-6019)
- CISA: Known Exploited Vulnerabilities Catalog
- MITRE ATT&CK: Abuse Elevation Control Mechanism
Related NHI Mgmt Group resources: Linux Privilege Escalation Techniques Guide · sudo and sudoers Security Guide · Linux Server Hardening Guide · Linux Capabilities Guide · SELinux Guide