Here's a fact that surprises most people: when you type your password into sudo, you don't see any feedback at all. No asterisks, no dots, nothing. The cursor just sits there. This design decision was made in the 1980s and has been confusing users for over four decades. People routinely think their terminal is frozen, type their password multiple times, or assume something is broken. Ubuntu finally decided to show asterisks by default — ending a 46-year tradition of silent password entry.
That one small change reveals something bigger: the way Linux handles privilege escalation is a patchwork of decisions made across decades, some brilliant, some deeply questionable, all carrying the weight of backward compatibility. Understanding how we got here helps you make better security decisions today.
Before sudo: The World of su
The original Unix privilege escalation tool was su — "substitute user." It did exactly one thing: switch your entire shell session to another user, typically root. You'd type su, enter root's password, do your admin work, and then exit back to your normal account.
$ su
Password: [type root's password]
# whoami
root
# apt install nginx
# exit
$ whoami
normaluser
The problems with su became obvious as Unix systems grew beyond a handful of trusted operators. Everyone who needed admin access had to know root's password. When someone left the team, you had to change the root password and distribute the new one to everyone else. There was no audit trail — once someone became root, all their actions were logged as "root" with no record of who actually ran what. And su gave you a full root shell, which meant a single typo could destroy the system.
The classic horror story: an admin meant to type rm -rf /tmp/old_files but accidentally hit enter after rm -rf /. With a full root shell, there's nothing stopping that command from executing. su made no distinction between "this person needs to restart nginx" and "this person needs unrestricted access to the entire system."
How sudo Fixed the Root Password Problem
sudo ("superuser do") was created in 1980 at SUNY Buffalo by Bob Coggeshall and Cliff Spencer. The core insight was simple but transformative: instead of sharing the root password, let individual users run specific commands as root using their own password. The system administrator controls who can run what through a configuration file.
This solved several problems at once:
- No shared root password. Each user authenticates with their own credentials. When someone leaves, you remove their sudo access. No password rotation needed.
- Granular permissions. You can allow a developer to restart a specific service without giving them full root access.
- Audit trail. Every sudo command is logged with the username of who ran it, what they ran, and when.
- Temporary escalation. Instead of an open-ended root shell, sudo runs a single command with elevated privileges and then drops back to normal.
# Run a single command as root
$ sudo apt install nginx
[sudo] password for priya:
# That's YOUR password, not root's
# The audit trail in /var/log/auth.log:
# Mar 20 14:23:01 web-03 sudo: priya : TTY=pts/0 ;
# PWD=/home/priya ; USER=root ; COMMAND=/usr/bin/apt install nginx
The sudoers File: Powerful and Dangerous
sudo's configuration lives in /etc/sudoers, and its syntax is genuinely one of the most confusing things in Linux administration. A single syntax error can lock you out of sudo entirely, which is why the visudo command exists — it validates the file before saving.
# /etc/sudoers syntax:
# WHO WHERE = (AS_WHOM) WHAT
# Let priya run anything as root on any host
priya ALL=(ALL:ALL) ALL
# Let the 'webdev' group restart nginx only
%webdev ALL=(root) /usr/bin/systemctl restart nginx,\
/usr/bin/systemctl reload nginx
# Let deploy user run deploys without a password
deploy ALL=(root) NOPASSWD: /opt/deploy/run.sh
# DANGEROUS: This looks restrictive but isn't
bob ALL=(root) /usr/bin/vim
# Bob can now run: sudo vim, then :!bash to get a root shell
That last example — giving someone sudo access to vim — is a security pitfall that catches people constantly. Vim (and many other programs) can spawn shell commands. If a user can sudo vim, they effectively have unrestricted root access. The same applies to less, man, awk, find, python, and dozens of other commands. The GTFOBins project maintains a comprehensive list of binaries that can be used to escape restricted shells.
sudo's Quirks and Security Pitfalls
sudo has accumulated some genuinely weird behavior over its 40+ year history. Understanding these quirks matters for security:
- Credential caching. After you enter your password, sudo caches it for 15 minutes by default. During that window, any sudo command runs without authentication. If you walk away from an unlocked terminal, anyone can run sudo commands for up to 15 minutes. Run
sudo -kto kill the cache immediately. - The tty_tickets setting. By default, sudo's credential cache is per-terminal. But on some systems, authenticating in one terminal session unlocks sudo in all of them. Check your
Defaultssettings. - Environment variables. sudo sanitizes most environment variables, but not all.
LD_PRELOADandLD_LIBRARY_PATHare stripped, but ifenv_keepis misconfigured, an attacker can inject malicious library paths. This has been the basis of several real privilege escalation exploits. - The NOPASSWD footgun.
NOPASSWDis convenient for automation but dangerous if applied too broadly. A compromised application running as a user withNOPASSWDsudo access effectively has root — no password to crack.
# Security hardening for sudoers:
# Require password every time (disable caching)
Defaults timestamp_timeout=0
# Or reduce cache to 1 minute
Defaults timestamp_timeout=1
# Ensure credential cache is per-terminal
Defaults tty_tickets
# Log all sudo I/O (records full terminal sessions)
Defaults log_input, log_output
Defaults iolog_dir=/var/log/sudo-io
# Require root password instead of user password
# (prevents compromised user accounts from sudo-ing)
Defaults rootpw
# Show asterisks when typing password
Defaults pwfeedback
Modern Alternatives: doas, polkit, and run0
sudo's complexity has spawned several alternatives, each taking a different philosophy.
doas: sudo Without the Complexity
OpenBSD's doas ("dedicated OpenBSD application subexecutor") was created by Ted Unangst in 2015 specifically because sudo had become too complex to audit. The entire configuration is typically 2-3 lines:
# /etc/doas.conf — the entire configuration
permit persist priya
permit nopass deploy as root cmd /opt/deploy/run.sh
# That's it. Compare this to a typical sudoers file.
# 'persist' is like sudo's credential caching
# 'nopass' is like NOPASSWD
The doas source code is about 2,500 lines of C. sudo's is over 150,000. For systems where you don't need sudo's advanced features (like per-command argument matching or LDAP integration), doas is dramatically simpler to configure, audit, and secure. I've been using it on my personal servers for years and haven't missed sudo once.
polkit: Fine-Grained Desktop Privileges
PolicyKit (polkit) takes a completely different approach. Instead of wrapping individual commands, it defines actions that applications can request. When a desktop app needs to modify network settings, it asks polkit for permission, and polkit decides based on its rules whether to grant it, deny it, or prompt the user.
This is how your Linux desktop lets you mount a USB drive without a password but requires authentication to install software. The granularity is at the action level, not the command level, which maps better to how desktop users actually think about permissions.
run0: systemd's Radical Rethink
systemd's run0 is the newest entry, and it works fundamentally differently from sudo. Instead of running a command as root from your existing session (which requires setuid bits and creates security headaches), run0 asks the service manager to spawn a new service that runs as root. Your user session never gains elevated privileges — the privileged process is completely separate.
This sidesteps entire categories of sudo vulnerabilities. There's no setuid binary, no credential caching, no environment variable injection surface. The trade-off is that it requires systemd, which makes it a non-starter for BSD systems and minimal Linux setups. But for systemd-based servers, it's arguably the most secure option available.
Practical Recommendations
After years of managing Linux servers and investigating privilege escalation incidents, here's what I actually recommend:
- Disable root login entirely. Use
sudoordoasfor everything. There should be no shared root password. - Use groups, not individual users, in sudoers. Manage access through group membership. When someone leaves, remove them from the group.
- Never give sudo access to interpreters or editors. No
sudo vim,sudo python,sudo less. If you need to edit a root-owned file, usesudoeditinstead. - Minimize NOPASSWD rules. Use them only for automated processes, and only for specific commands with full paths.
- Enable sudo logging. At minimum, log all sudo commands. For sensitive systems, enable full I/O logging.
- Consider doas for simpler systems. If you don't need LDAP integration or complex matching rules, doas is easier to get right.
- Rotate credential caches aggressively. Reduce
timestamp_timeoutto 1-5 minutes, or disable caching entirely on production servers.
The best privilege escalation mechanism is the one that grants the minimum access needed, for the minimum time needed, with a complete audit trail. Everything else is a compromise.
sudo isn't going anywhere. It's too deeply embedded in scripts, automation, documentation, and muscle memory to disappear. But the landscape of alternatives is healthier than it's ever been. Whether you stick with sudo (hardened properly), switch to doas (for simplicity), or adopt run0 (for security-critical systems), the important thing is understanding what your privilege escalation tool actually does — because the gap between what people think sudo does and what it actually does is where most security incidents live.