← All rules
SOCLE-CLD-GEN-038// Hardening (misc)mediuminventory state

Ensure shadow Group is Empty

Ensures the shadow group has no members, so no user gains read access to /etc/shadow and its password hashes.

Checked against what is installed or registered, packages present/absent, account databases.

A pass proves✓ running now✓ on disk✓ survives rebootthe qualified verdict →
Debian 12CIS 1.1.0Debian 13CIS 1.0.0FedoraRHEL 10 / Rocky 10 / AlmaLinux 10RHEL 8 / Rocky 8 / AlmaLinux 8CIS 4.0.0RHEL 9 / Rocky 9 / AlmaLinux 9CIS 2.0.0Ubuntu 22.04CIS 3.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04
One check, maps to 2 standards

A mapping is a cross-reference to where each standard places this requirement, anchored and cross-validated, not a claim of equivalence. A passing check is evidence toward these references, how to read it.

Why this rule matters

On Debian/Ubuntu the /etc/shadow file is group-owned by shadow and readable by that group. Any user placed in the shadow group therefore gains read access to every account's hashed password and password-aging data. With that file in hand, an attacker can run an offline password-cracking tool against the hashes and use the aging/expiry fields to target additional accounts. The shadow group is meant to be used by daemons (via setgid binaries), not by people, so it should contain no members.

What Pavois checks

Pavois inspects the member field of the shadow entry as resolved on the live system. Reading the effective group membership matters because a user can also be in shadow as their primary group or via an NSS backend; the goal state is that no human account lists shadow among its supplementary groups.

describe command('awk -F: \'($1=="shadow"){print $4}\' /etc/group') do
  its('stdout.strip') { should eq '' }
end

How to verify it is applied

List the shadow group and confirm the member field is empty:

  • getent group shadow, expected output ends with an empty field, e.g. shadow:x:42: (nothing after the last colon).
  • awk -F: '($1=="shadow"){print $4}' /etc/group, expected output is empty.

Inspect & investigate

Group membership changes are recorded by user-management tooling:

  • grep -E 'shadow' /var/log/auth.log, shows usermod/gpasswd actions touching the shadow group.
  • getent group shadow is the authoritative current-state command; compare it before and after any change.

Remediation

No automated harden plan is defined for this rule yet, so it must be applied manually: remove every user from the shadow group with gpasswd --delete <user> shadow (and fix any account whose primary group is shadow with usermod -g <other> <user>) until getent group shadow shows no members.

Pavois applies this with its own harden engine, the plan below, not a shell script:

commandgetent group shadow # gpasswd -d <user> shadow for each unexpected member
reasonremoving members from the shadow group is deliberate (they lose shadow access)
resourcemanual
pavois harden plan local

where the target is local, a user@host SSH alias, or a container , Docs

Impact & precautions

Risk if not applied: any shadow-group member can read every password hash on the host, enabling offline cracking and lateral movement.

Precautions before applying: check why each member was added, some legacy tools or monitoring agents may rely on shadow read access. Move those to a dedicated setgid helper or grant access narrowly instead of leaving humans in the group. Removing members is non-disruptive to login itself, since /etc/shadow reads by PAM happen as root, not via the group.

Standards mapping

StandardReferenceTypeVersionConfidence
CIS7.2.4, 8.3.2directper OS, see the benchmark tablehigh
PCI DSS8.3.2supporting4.0.1medium

Each reference is a cross-reference anchored in the upstream benchmark and cross-validated against the SCAP Security Guide and ansible-lockdown, not a claim of equivalence. Direct = a prescriptive, line-level requirement; supporting = an abstract control family (NIST) the check provides evidence toward. How to read a mapping.

Sources & references