Local account drift can turn a routine Linux review into an access-control problem when old users, service accounts, or unexpected administrator grants remain on a host. Auditing the account database shows which names can log in, which accounts hold privileged identifiers, and which password states need follow-up before a handoff or incident review.

Account records come from the system password database visible through Name Service Switch, while password lock and aging data live in /etc/shadow on systems that use the shadow suite. The local files show login shell, home directory, UID, primary group, and supplementary group membership; directory-backed identities may also appear through getent depending on /etc/nsswitch.conf.

Read /etc/shadow and sudoers data with root privileges only on systems where that access is authorized. Password hashes, account names, home paths, sudo rules, and login sources can identify people or expose privilege paths, so copy only the findings needed for the ticket or audit record.

Steps to audit local user accounts in Linux:

  1. List account records from the system password database.
    $ getent passwd
    root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    sys:x:3:3:sys:/dev:/usr/sbin/nologin
    sync:x:4:65534:sync:/bin:/bin/sync
    ##### snipped #####
    ubuntu:x:1000:1000:Ubuntu:/home/ubuntu:/bin/bash
    analyst:x:1001:1001::/home/analyst:/bin/bash
    deploy:x:1002:1002::/home/deploy:/bin/bash
    appsvc:x:1003:1003::/home/appsvc:/usr/sbin/nologin

    getent passwd shows the account database visible to system tools. On hosts using LDAP, SSSD, or another NSS source, compare this output with /etc/passwd when the audit must separate local file accounts from directory accounts.

  2. Identify the regular-user UID range defined by the system policy.
    $ grep --extended-regexp '^UID_(MIN|MAX)' /etc/login.defs
    UID_MIN			 1000
    UID_MAX			60000

    Use these values for the range checks below. Many Debian and Ubuntu systems use 1000 through 60000 for regular users, but local policy can change them.

  3. List regular local accounts by UID, home directory, and shell.
    $ awk -F: '$3 >= 1000 && $3 <= 60000 {printf "%s:%s:%s:%s\n", $1, $3, $6, $7}' /etc/passwd
    ubuntu:1000:/home/ubuntu:/bin/bash
    analyst:1001:/home/analyst:/bin/bash
    deploy:1002:/home/deploy:/bin/bash
    appsvc:1003:/home/appsvc:/usr/sbin/nologin

    Replace 1000 and 60000 when /etc/login.defs uses different values.

  4. Review ownership and permissions for regular users' home directories.
    $ sudo ls -ld /home/*
    drwxr-x--- 2 analyst analyst 4096 Jun 13 21:25 /home/analyst
    drwxr-x--- 2 deploy  deploy  4096 Jun 13 21:25 /home/deploy
    drwxr-x--- 2 ubuntu  ubuntu  4096 Apr 21 15:27 /home/ubuntu

    World-writable homes or homes owned by the wrong account can let another local user plant shell startup files, SSH keys, or persistence scripts.

  5. Find local accounts outside the regular-user UID range that do not use nologin or false.
    $ awk -F: '($3 < 1000 || $3 > 60000) && ($7 !~ /(nologin|false)$/) {printf "%s:%s:%s:%s\n", $1, $3, $6, $7}' /etc/passwd
    root:0:/root:/bin/bash
    sync:4:/bin:/bin/sync

    Expect root. Other package or service accounts may use narrow commands such as /bin/sync, but any unexpected shell-capable system account needs an owner and purpose.

  6. Identify every account with UID 0.
    $ awk -F: '$3 == 0 {printf "%s:%s:%s\n", $1, $6, $7}' /etc/passwd
    root:/root:/bin/bash

    Any account other than root with UID 0 has root-equivalent privileges and should be treated as a high-severity finding.

  7. List accounts in the sudo group.
    $ getent group sudo
    sudo:x:27:ubuntu,deploy

    sudo is the common administrative group on Debian and Ubuntu systems.

  8. List accounts in the wheel group when the distribution uses it.
    $ getent group wheel

    No output means the group is absent or has no visible entry in the active group database. wheel is common on RHEL, CentOS, Fedora, and related systems.

  9. Check effective sudo permissions for an account that needs review.
    $ sudo -l -U deploy
    User deploy may run the following commands on server:
        (ALL : ALL) ALL
        (ALL) NOPASSWD: /usr/bin/systemctl status app.service

    Unexpected user-specific rules, broad ALL command grants, or NOPASSWD entries can provide administrative access outside group membership.

  10. Review password lock state for all visible accounts.
    $ sudo passwd --status --all
    root L 2026-04-21 0 99999 7 -1
    daemon L 2026-04-21 0 99999 7 -1
    bin L 2026-04-21 0 99999 7 -1
    sys L 2026-04-21 0 99999 7 -1
    ##### snipped #####
    ubuntu L 2026-04-21 0 99999 7 -1
    analyst L 2026-06-13 0 99999 7 -1
    deploy L 2026-06-13 0 99999 7 -1
    appsvc L 2026-06-13 0 99999 7 -1

    The second field reports P for a usable password, L for a locked password, and NP for no password. A locked password does not necessarily block SSH keys or other authentication tokens.

  11. Find accounts with an empty /etc/shadow password field.
    $ sudo awk -F: '$2 == "" {print $1}' /etc/shadow

    No output means no empty shadow password fields were found.

    An empty password field can allow passwordless authentication when the login stack permits it.

  12. Review password aging and expiry policy for an account that needs follow-up.
    $ sudo chage --list --iso8601 deploy
    Last password change					: 2026-06-13
    Password expires					: never
    Password inactive					: never
    Account expires						: never
    Minimum number of days between password change		: 0
    Maximum number of days between password change		: 99999
    Number of days of warning before password expires	: 7

    Replace deploy with the target account. chage reads shadow password aging data and does not prove every login path on systems that also use directory services, SSH keys, or external identity providers.