Skip to content

A long sudo credential cache is unlimited root for every process you run

scope: generic · severity: trap · confidence: proven · subsystem: setup

pmbootstrap needs root, and the obvious way to stop it prompting is:

Defaults:you timestamp_timeout=9999

That is a 167-hour root credential cache, and it is not scoped to pmbootstrap. It is scoped to you. For a week, anything running under your account gets silent root with no prompt, no allowlist and no audit trail: an agent, a build script, a compromised dependency, a prompt injection that arrived in a log file something read.

The failure mode is not “the agent turns evil”. It is that the blast radius of any mistake, from any source, becomes the whole machine — and you cannot afterwards tell what used it.

The intercept. pmbootstrap escalates through exactly one hook:

def sudo(cmd):
sudo = which_sudo() # honours $PMB_SUDO
return [sudo, *cmd] if sudo else cmd

So PMB_SUDO=<broker> routes every root request through a program you control, as argv, which you can validate. It is a supported upstream feature.

The surface is smaller than it looks. A real pmbootstrap chroot -- true plus shutdown makes 72 root requests across 11 verbs (mount, umount, sh, mknod, chmod, ln, rm, mkdir, touch, env, losetup), and every path argument is inside the pmbootstrap work directory. Measure it on your own setup rather than trusting that list.

The remedy is to need no root at all. porthole sandbox up runs the work in a persistent rootless container where you are uid 0 inside and your own unprivileged uid outside, so pmbootstrap uses no sudo whatsoever and no sudoers entry is granted. An escape reaches your uid, not the machine.

A validating broker was tried and then deleted, 2026-08-29. PMB_SUDO pointed at a program that confined paths to declared roots, refused non-pmbootstrap verbs and audited every decision — far better than a blanket cache, and still not enough. chroot <dir> <cmd> runs an arbitrary command as root, and root inside a chroot can escape a chroot; a broker confines the directory, not the payload. Since pmbootstrap legitimately needs to write executables into a chroot and run them, any allowlist that lets pmbootstrap work lets a payload work.

So the remaining lesson is sharper than “broker it”: a fallback that still exists is the one a stuck agent reaches for, and one that buys false confidence is worse than none. Removing it left exactly one answer.

The one thing worth doing even if you do nothing else: delete the timestamp_timeout line. A five-minute cache instead of a week-long one turns every escalation after the first into one you were present for.

Generalises past pmbootstrap: the same shape applies to any agentic workflow that needs a privileged tool — Docker socket access, terraform apply, kubectl with cluster-admin. Ask what the tool actually needs, discover it empirically, and give it exactly that – or, better, an environment where it needs no privilege to give.

Related: no-passwordless-sudo-disables-the-whole-toolbox, running-a-device-script-on-the-host.