HardStacked
Share:

Attack surface · sudo

sudo NOPASSWD not working: sudo still asks for a password (Ubuntu 24.04, Debian 13)

Published · HardStacked · 7 min

You wrote user ALL=(ALL) NOPASSWD: ALL, it worked before, and now sudo asks for a password. In a container or a script, with no terminal, it prints sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper, then sudo: a password is required. The question has been on askubuntu since 2024-07-31 (question 1522123, 10 930 views when we read it on 2026-10-26, four answers, none accepted), and the person who asks puts it in one sentence:

"This works in previous versions, (22.04, 20.04) but in Ubuntu 24.04 I'm getting this error"

Your rule is fine, and sudo read it. Another rule that also applies to you is read after it, and sudo applies the last rule that matches, not the most specific one. Worse, sudo -l shows NOPASSWD: ALL while sudo asks for the password anyway. The line that counts is the last one. Everything below was measured on a Raspberry Pi under Debian 13, sudo package 1.9.16p2-3+deb13u2, on 2026-10-26.

01. A test that cannot lock you out

We reproduce it with a dedicated user demo (no password) and a dedicated group demoadm, and every file we create has demo in its name. The trap deliberately does not use %sudo: if it did, and your own access depends on the order of rules, you could cut your own sudo during the test and be unable to undo it. Here, only demo is affected. And since demo has no password, if sudo asks it for one it can never answer, which is the proof. sudo -n means non-interactive: it fails instead of waiting.

the lab
$ sudo groupadd demoadm
$ sudo useradd -m -G demoadm demo
$ echo 'demo ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/05-demo
demo ALL=(ALL) NOPASSWD: ALL
$ sudo chmod 0440 /etc/sudoers.d/05-demo
$ sudo -u demo sudo -n true && echo 'no password asked'
no password asked

One rule, in its own file, and it works. Nothing surprising yet.

02. sudo: a password is required

Now add a second rule that concerns demo through its group. It sits in a file named 10-demo-group, which sorts after 05-demo:

a second rule, by group
$ echo '%demoadm ALL=(ALL:ALL) ALL' | sudo tee /etc/sudoers.d/10-demo-group
%demoadm ALL=(ALL:ALL) ALL
$ sudo chmod 0440 /etc/sudoers.d/10-demo-group
$ sudo -u demo sudo -n true && echo 'no password asked'
sudo: a password is required

The NOPASSWD rule is still there, untouched. Without a terminal, the same thing gives the exact message of the question:

no terminal
$ sudo -u demo sudo true </dev/null
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper sudo: a password is required

The man page of sudoers (Debian 13) says it plainly: "When multiple entries match for a user, they are applied in order. Where there are multiple matches, the last match is used (which is not necessarily the most specific match)." A group rule without NOPASSWD, read last, replaces your user rule that was more precise.

03. sudo -l lists both rules, and the last one wins

This is the part that makes people doubt their own eyes. Ask sudo what demo may run (the sed cuts the lines that depend on each machine, like the Defaults; you will see your own machine name where we have debian):

sudo -l
$ sudo -l -U demo | sed -n '/^User/,$p'
User demo may run the following commands on debian: (ALL) NOPASSWD: ALL (ALL : ALL) ALL

NOPASSWD: ALL is listed, and sudo asks for the password. The list is in the order the rules were read, so the line that applies is the bottom one. On a real machine you may not know which file a rule comes from. sudo -ll tells you, once the output is filtered to the lines that name the file:

sudo -ll: which file
$ sudo -ll -U demo | grep 'Sudoers entry'
Sudoers entry: /etc/sudoers.d/05-demo Sudoers entry: /etc/sudoers.d/10-demo-group

On Debian 13, /etc/sudoers ends with @includedir /etc/sudoers.d, which is what /etc/sudoers.d/README describes. So every file in sudoers.d is read after everything in /etc/sudoers, including its %sudo ALL=(ALL:ALL) ALL line. That is why putting your line "after %sudo" inside /etc/sudoers is not always enough. We measured the fact that sudo -ll names the file on sudo 1.9.16p2; we do not know from which version it does.

04. A file name with a dot is never read

Second trap, same page. The man page says sudo reads the files of /etc/sudoers.d in sorted lexical order, "skipping file names that end in `~' or contain a `.' character". So 99-demo.conf does not exist for sudo. Let us rename our NOPASSWD file that way:

renamed 99-demo.conf
$ sudo mv /etc/sudoers.d/05-demo /etc/sudoers.d/99-demo.conf
$ sudo visudo -c | grep demo
/etc/sudoers.d/10-demo-group: parsed OK
$ sudo -u demo sudo -n true && echo 'no password asked'
sudo: a password is required

visudo -c does not even list the file, and still answers OK (exit code 0). Nobody tells you a rule was dropped. The sorting is lexical too, not numeric: the man page's own example is that /etc/sudoers.d/1_whoops is loaded after /etc/sudoers.d/10_second.

05. The fix: a file that sorts last, with no dot

Put your rule in /etc/sudoers.d/, in a file without a dot whose name sorts after the others, here 99-demo, mode 0440. Then check two things: your file must appear in the parsed OK list, and your NOPASSWD line must be the last one in sudo -l.

the fix: 99-demo
$ sudo mv /etc/sudoers.d/99-demo.conf /etc/sudoers.d/99-demo
$ sudo visudo -c | grep demo
/etc/sudoers.d/10-demo-group: parsed OK /etc/sudoers.d/99-demo: parsed OK
$ sudo -u demo sudo -n true && echo 'no password asked'
no password asked
$ sudo -l -U demo | sed -n '/^User/,$p'
User demo may run the following commands on debian: (ALL : ALL) ALL (ALL) NOPASSWD: ALL

The order flipped in the list, and the password is no longer asked. To write your own rule, the standard form is sudo visudo -f /etc/sudoers.d/99-yourname, which checks the syntax before saving. Our bench used tee and chmod so that every step shows in the capture, and visudo -c afterwards.

06. What the answers say, and one security point

The most voted answer (score 8) quotes the same sentence of the manual and says to put your line after %sudo. True, but incomplete: a file of sudoers.d that matches you is read after all of /etc/sudoers and wins anyway. Another answer (score 4) reports a /etc/sudoers.d/10-installer on its author's machine containing %sudo ALL=(ALL:ALL) ALL, which overrode the rule. That is exactly our trap; we did not see that file ourselves, so check yours with sudo -ll. A third answer (score 0), posted by the asker, changes %sudo to NOPASSWD with sed. It works, and it gives passwordless root to every member of the sudo group. Prefer one rule per user, and if you can, only the commands your script needs. For example NOPASSWD: /usr/bin/systemctl restart nginx (this is the syntax, we did not run it).

07. Clean up, and what we did not test

The teardown removes our two files, the user and the group. The userdel warning is only about a mail spool that never existed. The last command proves demo is gone:

teardown
$ sudo rm /etc/sudoers.d/99-demo /etc/sudoers.d/10-demo-group
$ sudo userdel -r demo
userdel: demo mail spool (/var/mail/demo) not found
$ sudo groupdel demoadm
$ id demo
id: 'demo': no such user

Measured: a Raspberry Pi, Debian 13, sudo 1.9.16p2. Not measured: Ubuntu 24.04 itself (the rule is in the upstream sudoers manual, but we did not test that machine), and sudo-rs, the default sudo from Ubuntu 25.10 on. We measured sudo-rs since: on Ubuntu 26.04, a sudoers line with a wildcard is dropped whole.

Share: