# Privilege Dropping

Privilege dropping is the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) applied to a running process at the moment it starts. A program is handed whatever privileges its user has, which is almost always more than the job needs. Dropping means the process voluntarily narrows that set down to the minimum before it starts handling untrusted input, so that a later exploit — a poisoned message, a bad parse, a compromised dependency — inherits the narrowed set, not the original one.

The defining property across every mechanism is irreversibility. A dropped privilege cannot be reacquired. There is no call to undo a chroot, re-enter a pledge, or widen a Landlock ruleset; the filters are one-way ratchets that only tighten. That's what makes the technique worth anything — if an attacker who gets code execution could just ask for the privilege back, dropping it would be theatre.

Irreversibility forces a specific structure on the program. Everything privileged has to happen up front, during a startup phase, before the ratchet closes. A daemon binds its privileged port as root and keeps the file descriptor, *then* switches to an unprivileged user. It can still serve on the port it already holds but can never bind another. oxzi's image ([[go-privdrop]]) is an upside-down cone: start wide, drop along the way, run on the bare minimum.

## The capabilities that get shed

Different mechanisms narrow different axes, and a defence-in-depth setup stacks several:

- **User and group identity** — `setresuid`/`setresgid`/`setgroups` move the process to an unprivileged user, giving up root. POSIX, needs root to begin with.
- **Filesystem root and path visibility** — `chroot(2)` relocates the process root; OpenBSD `unveil(2)` and Linux Landlock build an allow-list of paths, defeating path traversal to things like `~/.ssh`.
- **The syscall set** — OpenBSD `pledge(2)` (string of promises), Linux seccomp BPF (a kernel-side BPF filter over syscall numbers and arguments). Restrict which kernel calls the process may make at all.
- **Resource limits** — `setrlimit(2)` caps CPU time and memory as hard limits, a safety net against resource-exhaustion attacks rather than an access boundary.
- **Network** — Landlock now restricts inbound/outbound TCP by port; FreeBSD `capsicum(4)` is a capability model covering this class more broadly.

## Where it fits

Privilege dropping is self-restriction from *inside* the process — the program chains itself up before the full moon, in oxzi's werewolf metaphor. That contrasts with external sandboxing, where a wrapper constrains the process from outside: [[bubblewrap-dev-env]] runs a program under a namespace jail it never asked for, and [[sandboxing-ai-agents]] surveys the outside-in layers (namespaces, microVMs, HTTP proxies, syscall rewriting) used to fence AI coding agents. The two compose — a process can be both externally jailed and internally self-restricting — but internal dropping needs cooperation from the program's author, which is its main limitation: you can't retrofit it onto a binary you don't build.

A related but distinct defence is shrinking the *value* of what's reachable rather than the reach itself. [[ephemeral-credentials]] does that — a leaked short-lived token expires before it spreads — and pairs naturally with dropping, which reduces what an exploit can touch in the first place.

## Related

- [[go-privilege-dropping]] — the concrete Go implementation of every mechanism here, via `x/sys/unix`
- [[sandboxing-ai-agents]] — external, outside-in isolation; the complement to internal self-restriction
- [[syscall-binary-rewriting]] — another syscall-interception mechanism, applied from a supervising process
- [[bubblewrap-dev-env]] — namespace-based external jailing on Linux
