Home / Alt manpages / pkexec(1)

  • pkexec(1)
  • User command
  • linux

Run One Command Safely with pkexec

pkexec runs one named command as root, or another user, without opening a full sudo shell around it. You will start a command, check what happened, and learn why pkexec refuses to run something before it even starts. This guide targets pkexec 124 from the Ubuntu package pkexec 124-2ubuntu1.24.04.4; allow about ten minutes for a careful first test. You need an installed polkit policy and an authentication agent, or a terminal agent you deliberately start for this session.

Safety boundary

Pkexec starts a privileged process. Inspect the complete program path and every argument before authenticating. The examples below use read-only commands and do not alter system configuration.

1. Confirm the installed command

Run this as your ordinary user. Do not add sudo; the point is to let polkit decide whether authentication is needed.

$ command -v pkexec
/usr/bin/pkexec
$ dpkg-query -W -f='${Package} ${Version}\n' pkexec
pkexec 124-2ubuntu1.24.04.4
$ pkexec --version
pkexec version 124

The local manual documents --version, --help, --disable-internal-agent, --keep-cwd and --user. Once the target program is identified, everything after it on the command line belongs to that program, not to pkexec.

Checkpoint

You are using /usr/bin/pkexec, and its version is known.

2. Run a harmless command as root

Use an absolute path for the child. id only reports identity, so it makes a safe smoke test, and the default target user is root when --user is left out.

$ pkexec /usr/bin/id
uid=0(root) gid=0(root) groups=0(root)

Your groups and formatting may differ; the result you want is uid 0 and a clean exit. Depending on your session, a graphical agent pops the prompt, or pkexec 124 falls back to its own textual one.

A successful prompt here is not a blank cheque. Every later command still gets the same scrutiny: check the path and arguments each time, not just the first time.

3. Check the exit status separately

pkexec normally hands back the child program's own exit status. Capture it straight after the command if a script needs to tell success from failure.

$ pkexec /usr/bin/sh -c 'exit 7'
$ printf 'child status: %s\n' "$?"
child status: 7

That shell is given a fixed command here, never user input, and status 7 is simply what the child chose to return. Two numbers belong to pkexec itself: 127 when authorisation cannot be obtained or something else stops execution, and 126 when you dismiss the authentication dialog. Do not treat either number as a diagnosis; log what actually happened.

4. Choose another target user explicitly

Use --user when the command should run as a named account that already exists, and that the active policy already permits.

$ pkexec --user root /usr/bin/id -un
root

That repeats the default, but it makes the intended identity visible in a script or runbook, which matters more than it sounds. For a non-root account, swap in a real local user name and check it first:

$ pkexec --user BACKUP_USER /usr/bin/id -un
BACKUP_USER

BACKUP_USER is a placeholder, not a real account. Verify it exists before you run anything against it:

$ getent passwd BACKUP_USER
BACKUP_USER:x:1002:1002:Backup account:/home/BACKUP_USER:/usr/sbin/nologin

Do not create or edit an account merely to make this example work. If getent prints nothing, stop, and use an account your administrator has actually provisioned.

5. Mind the working directory

By default pkexec runs the child in the target user's home directory, which is a nasty surprise for anything using relative paths. Use absolute paths for the program and any files it touches, or add --keep-cwd when keeping your own current directory is genuinely what you want.

$ pwd
/srv/example
$ pkexec /usr/bin/pwd
/root
$ pkexec --keep-cwd /usr/bin/pwd
/srv/example

--keep-cwd only changes where the privileged process starts, not which files its arguments point at. Review paths and permissions before you authenticate. If something wrote to the wrong place, stop it if it is still running and restore the file from your normal backup: there is no general undo for a command that pkexec has already run.

6. Treat the environment and arguments as security boundaries

pkexec hands the child a minimal, known environment instead of passing through variables like LD_LIBRARY_PATH, and it sets PKEXEC_UID to the uid of the process that invoked it. A privileged program should never assume your ordinary shell's aliases, search path or environment came along for the ride.

That same stripped environment is why ordinary X11 applications usually will not display through pkexec: DISPLAY and XAUTHORITY are gone. A policy action can explicitly keep them with the org.freedesktop.policykit.exec.allow_gui annotation, but the manual discourages that outside legacy programs. Do not "fix" a GUI failure by smuggling your own authentication variables into a privileged command.

pkexec does not validate what it hands to the child. That matters most when a policy lets a user retain authorisation, or authorises a rule implicitly: a rule that lets a script take arbitrary arguments can be as dangerous as a root shell, if that script handles bad input poorly. Keep the program path fixed, quote your data, and never build a privileged command from unchecked text.

7. Diagnose a failed authentication attempt

Run this from a real terminal to see whether an agent is even available:

$ pkexec /usr/bin/true
Error creating textual authentication agent: Error opening current controlling terminal for the process (`/dev/tty'): No such device or address
$ printf 'pkexec status: %s\n' "$?"
pkexec status: 127

The exact wording depends on the session. On a graphical desktop, check that a polkit agent is actually running; inside a service, container or non-interactive job, there may be no agent at all. A terminal agent can be registered separately with pkttyagent, but that is a session-setup decision, not something to bolt onto an automation script without thinking.

--disable-internal-agent stops pkexec registering its own fallback textual agent. Use it only when something else is deliberately managing authentication for the calling environment; it never bypasses authentication itself.

Done means

  • You checked the installed path and version of pkexec before relying on it.
  • You reviewed the full command before authenticating, every time.
  • You verified the target identity and, where relevant, the working directory.
  • You can tell the child's exit status apart from pkexec's own authentication failures.
  • You know the environment is sanitised and that GUI variables are normally stripped out.
  • You have not relied on unchecked arguments or assumed a privileged command has an automatic undo.