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

Ensure the Group Used by pam_wheel.so Module Exists on System and is Empty

Ensures the group referenced by pam_wheel.so in /etc/pam.d/su exists and has no members, so no user can escalate to root through su.

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

The su program runs commands with a substitute user and group ID, and is the classic way to become root. The pam_wheel.so module restricts who may run su to members of a named group (e.g. wheel or sugroup). If that group is configured but empty, no unprivileged user can pivot to root through su, privilege escalation must go through sudo, which is logged and per-command. A populated wheel group silently grants its members an unaudited path to full root.

What Pavois checks

Pavois reads the effective PAM configuration: it extracts the group= argument actually passed to pam_wheel.so in /etc/pam.d/su, then resolves that group through getent group (NSS) and checks its member field is empty. Resolving via getent rather than only parsing /etc/group is what catches members coming from LDAP, SSSD or other NSS backends that a flat file scan would miss.

describe command('g=$(grep -RhoE \'pam_wheel.so.*group=[a-z]+\' /etc/pam.d/su 2>/dev/null | grep -oE \'group=[a-z]+\' | cut -d= -f2 | head -1); { [ -n "$g" ] && [ -z "$(getent group "$g" | cut -d: -f4)" ] && echo ok; } || echo ko') do
  its('stdout.strip') { should eq 'ok' }
end

How to verify it is applied

Find the group enforced by PAM and list its members:

  • grep -E 'pam_wheel.so.*group=' /etc/pam.d/su, read the configured group name (e.g. group=sugroup).
  • getent group sugroup, expected output ends with an empty member field, e.g. sugroup:x:1001: (nothing after the last colon).

Inspect & investigate

PAM su events are logged by the authentication stack:

  • journalctl -t su or grep ' su' /var/log/auth.log (Debian/Ubuntu) / /var/log/secure (RHEL), shows pam_wheel(su:auth): Access denied ... when a non-member is correctly rejected.
  • Successful escalations appear as su: (to root) <user> on pts/N.

Remediation

No automated harden plan is defined for this rule yet, so it must be applied manually: identify the group named in /etc/pam.d/su (group=), then remove every member with gpasswd --delete <user> <group> (or edit the group's member list) until getent group <group> shows no members. Ensure the group still exists.

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

commandgetent group wheel # gpasswd -d <user> wheel for each unexpected member
reasonremoving wheel members revokes their su access, confirm each
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: members of the wheel/su group hold an unaudited, full-root escape hatch via su even when sudo policy is tight.

Precautions before applying: before emptying the group, confirm that every administrator can still reach root another way, typically a working sudo rule. Removing the last member while sudo is broken or while pam_wheel.so is also enforced on the sudo stack can lock all admins out of privilege escalation. Keep a root console session open while you make the change.

Standards mapping

StandardReferenceTypeVersionConfidence
CIS2.2.6, 5.2.7directper OS, see the benchmark tablehigh
PCI DSS2.2.6supporting4.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