Skip to Content
OpenVAPTAlpha
Pre-release. Academic, non-commercial, source-available code built by AI Cybersecurity Engineers. Free for your own use, 100% at your own risk. This website collects no data. Read MoreRead Less
Pre-release. OpenVAPT has no Stable release yet. Every build is an Alpha, Beta or Release Candidate: it may be incomplete or wrong, so use it only on test machines, 100% at your own risk. See Release Channels
Academic, non-commercial, source-available code built by AI Cybersecurity Engineers. These are AI systems, not people or registered engineers. Free for your own personal or business use, on your own machines, 100% at your own risk. Not for sale. Not for providing services. This website collects no data. Read the Acknowledgements
Pre-release. OpenVAPT has no Stable release yet. Every build is an Alpha, Beta or Release Candidate: it may be incomplete or wrong, so use it only on test machines, 100% at your own risk. See Release Channels
Academic, non-commercial, source-available code built by AI Cybersecurity Engineers. These are AI systems, not people or registered engineers. Free for your own personal or business use, on your own machines, 100% at your own risk. Not for sale. Not for providing services. This website collects no data. Read the Acknowledgements
HighHOST-USR-003Identity and AuthenticationServer

Sudo Rules Without Password (NOPASSWD)

Checks sudoers files for rules that grant root without asking for a password.

Why It Matters
NOPASSWD means anyone who takes over that user (a stolen SSH key, a hijacked session, a web shell running as that user) becomes root instantly.
How It Detects
Reads /etc/sudoers and /etc/sudoers.d/* and lists active lines containing NOPASSWD.
How to Fix
Edit with visudo and remove NOPASSWD, or restrict it to one specific, harmless command for automation accounts.
How to Verify
grep -r NOPASSWD /etc/sudoers /etc/sudoers.d should print nothing, or only narrowly scoped commands.
CVSS v3.1 Vector
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Control Category
Identity and Authentication: CIS Controls v8 5, 6; NIST CSF 2.0 PR.AA
Fix Effort
Low
CIS Controls v8 Safeguard
5.4
NIST CSF 2.0 Subcategory
PR.AA-05
CWE
CWE-306
NIST SP 800-53 Rev. 5
AC-6, IA-11
Benchmark Topic
Sudo: re-authentication for privilege escalation (topic only, no benchmark text)
References
sudoers(5) manual
Learn the theory behind this check: F1 Security Basics, P7 Identity, Passwords and Privilege, P15 Access Control: Accounts, Sudo and Logins.

Source Code

The complete file that defines this check. Run it with openvapt scan --only HOST-USR-003, or read it offline with openvapt explain HOST-USR-003.

internal/checks/host/accounts.go · Lines 1-128View on GitHub at This Commit
1package host
2
3import (
4 "context"
5 "strings"
6
7 "github.com/openvapt/openvapt/internal/check"
8 "github.com/openvapt/openvapt/internal/sys"
9)
10
11func init() {
12 check.Register(&check.Check{
13 ID: "HOST-USR-001",
14 Title: "Extra Accounts With Root Privileges (UID 0)",
15 Domain: check.DomainHost,
16 Severity: check.High,
17 CVSS: "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
18 Summary: "Checks /etc/passwd for accounts other than root that have user id 0.",
19 Rationale: "Any account with UID 0 is root, whatever its name. Extra UID 0 accounts are a classic backdoor and bypass sudo logging.",
20 Detection: "Reads /etc/passwd and lists every entry whose third field (UID) is 0, other than 'root'.",
21 Fix: "Investigate who created each account. Remove it (userdel <name>) or give it a normal UID (usermod -u <new-uid> <name>). Grant admin rights through sudo instead.",
22 Verify: "awk -F: '$3==0' /etc/passwd should print only the root line.",
23 Refs: []check.Ref{{Title: "passwd(5), Linux man-pages", URL: "https://man7.org/linux/man-pages/man5/passwd.5.html"}, refNIST80053},
24 Standards: check.Standards{CWE: []string{"CWE-250", "CWE-266"}, NIST: []string{"AC-2", "AC-6"}, CISTopic: "User accounts: root is the only UID 0 account"},
25 Run: func(ctx context.Context, s sys.System) []check.Result {
26 r, err := s.ReadFile(ctx, "/etc/passwd")
27 if err != nil {
28 return []check.Result{check.ErrR("/etc/passwd", err)}
29 }
30 var extra []string
31 if !r.Complete {
32 return []check.Result{check.IncompleteR("/etc/passwd", "File was truncated while reading")}
33 }
34 for _, line := range strings.Split(string(r.Data), "\n") {
35 f := strings.Split(line, ":")
36 if len(f) >= 4 && f[2] == "0" && f[0] != "root" {
37 extra = append(extra, f[0]+":x:0:"+f[3])
38 }
39 }
40 if len(extra) > 0 {
41 return []check.Result{check.FailR("/etc/passwd", "Accounts other than root have UID 0", extra...)}
42 }
43 return []check.Result{check.PassR("/etc/passwd", "Only root has UID 0")}
44 },
45 })
46
47 check.Register(&check.Check{
48 ID: "HOST-USR-002",
49 Title: "Accounts Without a Password",
50 Domain: check.DomainHost,
51 Severity: check.High,
52 CVSS: "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
53 Summary: "Checks /etc/shadow for accounts whose password field is empty.",
54 Rationale: "An empty password field means the account can log in with no password at all on any service that allows password logins. The score uses a local attack vector: any local user can switch to the account (su) without a password, while the SSH daemon refuses empty passwords unless PermitEmptyPasswords is yes. If HOST-SSH-003 also fails, the same account is open from the network and should be treated as Critical.",
55 Detection: "Reads /etc/shadow (needs root) and lists entries whose second field is empty. Locked ('!' or '*') entries pass. Hashes are never copied into the report.",
56 Fix: "For each listed user either set a password (passwd <user>) or lock the account (passwd -l <user>).",
57 Verify: "awk -F: '$2==\"\"' /etc/shadow should print nothing.",
58 Refs: []check.Ref{{Title: "shadow(5), Linux man-pages", URL: "https://man7.org/linux/man-pages/man5/shadow.5.html"}},
59 Standards: check.Standards{CWE: []string{"CWE-258", "CWE-521"}, NIST: []string{"IA-5"}, CISTopic: "User accounts: password fields are not empty"},
60 Run: func(ctx context.Context, s sys.System) []check.Result {
61 r, err := s.ReadFile(ctx, "/etc/shadow")
62 if err != nil {
63 return []check.Result{check.SkipR("/etc/shadow", "Not readable (run as root for this check)")}
64 }
65 var empty []string
66 if !r.Complete {
67 return []check.Result{check.IncompleteR("/etc/shadow", "File was truncated while reading")}
68 }
69 for _, line := range strings.Split(string(r.Data), "\n") {
70 f := strings.Split(line, ":")
71 if len(f) >= 2 && f[0] != "" && f[1] == "" {
72 empty = append(empty, f[0])
73 }
74 }
75 if len(empty) > 0 {
76 return []check.Result{check.FailR("/etc/shadow", "Accounts have an empty password", empty...)}
77 }
78 return []check.Result{check.PassR("/etc/shadow", "Every account has a password or is locked")}
79 },
80 })
81
82 check.Register(&check.Check{
83 ID: "HOST-USR-003",
84 Title: "Sudo Rules Without Password (NOPASSWD)",
85 Domain: check.DomainHost,
86 Severity: check.High,
87 CVSS: "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
88 Summary: "Checks sudoers files for rules that grant root without asking for a password.",
89 Rationale: "NOPASSWD means anyone who takes over that user (a stolen SSH key, a hijacked session, a web shell running as that user) becomes root instantly.",
90 Detection: "Reads /etc/sudoers and /etc/sudoers.d/* and lists active lines containing NOPASSWD.",
91 Fix: "Edit with visudo and remove NOPASSWD, or restrict it to one specific, harmless command for automation accounts.",
92 Verify: "grep -r NOPASSWD /etc/sudoers /etc/sudoers.d should print nothing, or only narrowly scoped commands.",
93 Refs: []check.Ref{{Title: "sudoers(5) manual", URL: "https://www.sudo.ws/docs/man/sudoers.man/"}},
94 Standards: check.Standards{CWE: []string{"CWE-306"}, NIST: []string{"AC-6", "IA-11"}, CISTopic: "Sudo: re-authentication for privilege escalation"},
95 Run: func(ctx context.Context, s sys.System) []check.Result {
96 files := []string{"/etc/sudoers"}
97 more, _ := s.Glob("/etc/sudoers.d/*")
98 files = append(files, more...)
99 var hits []string
100 readable := false
101 complete := true
102 for _, f := range files {
103 r, err := s.ReadFile(ctx, f)
104 if err != nil {
105 continue
106 }
107 readable = true
108 complete = complete && r.Complete
109 for _, line := range strings.Split(string(r.Data), "\n") {
110 t := strings.TrimSpace(line)
111 if !strings.HasPrefix(t, "#") && strings.Contains(t, "NOPASSWD") {
112 hits = append(hits, f+": "+t)
113 }
114 }
115 }
116 if !readable {
117 return []check.Result{check.SkipR("/etc/sudoers", "Not readable (run as root for this check)")}
118 }
119 if len(hits) > 0 {
120 return []check.Result{check.FailR("/etc/sudoers", "Sudo rules grant root without a password", hits...)}
121 }
122 if !complete {
123 return []check.Result{check.IncompleteR("/etc/sudoers", "One or more sudoers files were truncated")}
124 }
125 return []check.Result{check.PassR("/etc/sudoers", "No NOPASSWD sudo rules")}
126 },
127 })
128}

Also available as plain Markdown for notes, scripts and AI tools. Same facts, same source, no styling.

Cite This Page

If this page helped your work, please cite it. The version and web address are filled in; the access date is today's date in your browser. Every other style, and when credit is required, is on How to Cite OpenVAPT.

APA 7
OpenVAPT. (2026). HOST-USR-003 Sudo Rules Without Password (NOPASSWD) (Version 0.1.0-alpha.6). OpenVAPT Check Catalogue. Retrieved October 16, 2026, from https://openvapt.com/checks/HOST-USR-003.html

In text: (OpenVAPT, 2026). Accessed: the date shown is today's date from your own browser (the site's build date without JavaScript); change it to the day you read the page.

BibTeX
@misc{openvapt_host_usr_003,
  author       = {{OpenVAPT}},
  title        = {{HOST-USR-003 Sudo Rules Without Password (NOPASSWD)}},
  year         = {2026},
  howpublished = {\url{https://openvapt.com/checks/HOST-USR-003.html}},
  note         = {OpenVAPT Check Catalogue, version 0.1.0-alpha.6. Accessed 16 October 2026}
}

Accessed: the date shown is today's date from your own browser (the site's build date without JavaScript); change it to the day you read the page.

Citing OpenVAPT does not mean OpenVAPT endorses, approves or has reviewed your work.