DevTools Hub

Search tools

Search for a developer tool

Sudoers File Explained

Part of the Linux Security Toolkit

Almost every Linux administrative task eventually runs through sudo, and sudoers is the one file that decides who gets to run what as root. It's also one of the easiest files on a system to misconfigure in a way that looks completely reasonable at a glance — a single line granting access to one seemingly narrow command can amount to full root access, and the file's own syntax gives no visual warning when that happens. This post covers how sudoers is actually structured and the specific patterns that turn a working configuration into a privilege-escalation path.

The anatomy of a rule

The core building block of sudoers is a user specification line:

who  host = (runas) tag: command_list

A concrete example:

deploy  ALL=(ALL) NOPASSWD: /usr/bin/systemctl restart myapp

deploy is who the rule applies to — a username or a %group. ALL here is the host this rule applies on (sudoers supports per-host rules for a file shared across many machines via a central configuration system, though most single-server setups just use ALL). (ALL) is which user the command runs as — almost always root, but sudo can grant permission to run as any account, not only root. NOPASSWD: is a tag changing the default behavior (normally sudo re-prompts for a password); the command list at the end is what this rule actually grants — here, one specific command with one specific argument, nothing broader.

Why NOPASSWD: ALL is the pattern to watch for

Replace that command list with a bare ALL and the rule grants unrestricted, passwordless root access:

deploy  ALL=(ALL) NOPASSWD: ALL

This is sometimes genuinely intended — a personal single-user server where the owner doesn't want a password prompt for their own account is a defensible if aggressive choice. It's a much bigger problem when it's granted to a shared group (%wheel, %sudo) rather than one named account, since it then applies to every current and future member of that group — anyone added later for an unrelated reason inherits full, passwordless root with no additional review.

The command list is where the real scope lives

A grant that looks narrow can still amount to full access, depending on what the granted command is actually capable of. Two specific patterns matter:

  • Wildcards. /usr/bin/systemctl restart * looks scoped to restart operations, but the wildcard means it accepts any service name — including one that doesn't exist yet, or one whose restart hook does something unintended. A wildcard in a command spec is often more permissive than it looks at first read.
  • Escape-prone binaries. Granting /usr/bin/vim, /usr/bin/less, /usr/bin/find, or a handful of other standard Unix tools without restricting their arguments is a well-documented way to get a root shell through the back door — vim can execute a shell command from inside its own interface (:!bash), and several of these tools have similar documented escapes (cataloged at length by the GTFOBins project). The sudoers line itself never mentions a shell at all; the risk lives entirely in what the granted binary is capable of once it's running as root.

Defaults: the settings that change how everything else behaves

Defaults lines don't grant access directly — they change sudo's own behavior for every rule that follows. A few worth knowing specifically because disabling them removes a real safeguard:

Defaults env_reset        # clears the environment before running as root (default; good)
Defaults !authenticate    # disables the password prompt entirely (dangerous if set)
Defaults timestamp_timeout=-1   # cached credential never expires for the session

env_reset being active by default matters more than it looks: without it, a user's own environment variables — a manipulated PATH, a malicious LD_PRELOAD — could influence what a command actually does once it's running with root privileges. !authenticate removes the password confirmation for every rule that follows it in the file, effectively converting every grant below that line into a NOPASSWD-equivalent one, regardless of whether each individual rule says so.

Aliases: readable rules, at the cost of a layer of indirection

Rather than repeating the same list of users or commands across many lines, sudoers supports named aliases defined once and referenced everywhere:

User_Alias ADMINS = alice, bob
Cmnd_Alias SERVICES = /usr/bin/systemctl restart myapp, /usr/bin/systemctl status myapp

ADMINS ALL=(ALL) SERVICES

This reads cleanly and scales well as a file grows, but it comes with a real cost for anyone auditing the file by eye: the actual scope of a rule isn't visible on the line granting it — it depends entirely on how SERVICES or ADMINS happens to be defined, possibly many lines away, possibly in a different included file entirely. A rule that looks narrow at the point it's granted can be arbitrarily broad depending on what its aliases actually expand to, which is exactly why sudo -l — which shows the fully resolved result for the current user — is more trustworthy for understanding real access than reading alias definitions and mentally expanding them by hand.

Editing safely: always visudo, never a plain editor

visudo validates the file's syntax before it's saved and refuses to write a broken one — a typo in a rule, caught before it takes effect, rather than discovered the next time anyone tries to use sudo at all and finds it completely unusable. Editing sudoers with a plain text editor skips that check entirely; a single syntax mistake can lock every account's sudo access at once, recoverable only via a root console or a rescue boot.

Most modern distributions also support #includedir /etc/sudoers.d in the main file, letting individual scoped grants live in their own separate files rather than one growing monolith — each still edited with visudo -f pointed at the specific file, for the same syntax-safety reason.

Common mistakes

  • NOPASSWD: ALL granted to a group instead of a named user. Multiplies exposure to every current and future member of that group.
  • A wildcard command spec that's broader than it looks. Read every wildcarded grant as "anything matching this pattern," not "the specific thing I had in mind when I wrote it."
  • Granting a GTFOBins-listed binary unrestricted. The sudoers line itself gives no indication of the risk; it lives entirely in what the granted program can do once running as root.
  • Editing the file directly instead of through visudo. The single most avoidable way to lock out sudo access system-wide over a typo.
  • Trusting an alias name at face value instead of checking what it expands to. A grant that reads narrowly at the point it's applied can be arbitrarily broad depending on a User_Alias or Cmnd_Alias defined elsewhere in the file.

FAQ

Why must sudoers only be edited with visudo?

visudo validates the file's syntax before saving and refuses to write a broken file — editing sudoers directly with a text editor risks a typo silently leaving the file unparsable, which can lock out sudo access for every account on the system until someone fixes it via a root console or recovery mode.

What's the difference between sudo -l and reading the sudoers file directly?

sudo -l shows what the current user is actually allowed to run after aliases are expanded and Defaults are applied — the real, resolved answer. Reading the raw file shows the rules as written, which may reference aliases or depend on Defaults defined elsewhere in the file or in an included one.

Is granting a whole group sudo access worse than granting individual users?

Not inherently, but it multiplies exposure — a NOPASSWD: ALL grant to a group like %wheel or %sudo means every current and future member of that group gets it, including anyone added to the group later for an unrelated reason. The same grant to one named user is easier to reason about and easier to audit.

What does #includedir actually do?

It tells sudo to read every file in a directory (conventionally /etc/sudoers.d/) as additional sudoers rules, which is how most modern systems let a package or an administrator add a scoped grant without editing the main sudoers file directly. Files in that directory are typically required not to have a dot or a tilde in their name, or sudo silently skips them.

Are GTFOBins-style privilege escalations a real, current risk?

Yes — they're a well-documented, actively maintained category of technique (see the GTFOBins project) specifically cataloging standard Unix binaries that can be abused to break out of a restricted shell or escalate privileges when invoked in certain ways. Granting one of those binaries through sudo without restricting its arguments is a genuinely common way a seemingly narrow grant turns into full root access.

Try it yourself

Sudoers File Analyzer checks a sudoers file or snippet for every pattern covered here — NOPASSWD: ALL, dangerous Defaults, wildcards, and GTFOBins-style binaries — entirely in your browser. For how sudo fits into the broader picture, see Linux Security.

Related tools