Verify Who Owns /etc/shells File
Ensures the valid-login-shells list /etc/shells is owned by root (UID 0).
Checked against a path’s metadata, mode, owner, group, SUID/SGID.
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 /etc/shells file lists the full pathnames of valid login shells. It is consulted by programs such as chsh, FTP daemons and getusershell()-based services to decide whether an account is allowed an interactive shell. If a non-root account owns it, that user could add an arbitrary binary as a 'shell' to gain or broaden interactive access. Setting root (UID 0) as the owner protects this access-control list.
What Pavois checks
Pavois inspects the live filesystem with the InSpec file('/etc/shells') resource and asserts uid == 0, guarded by only_if so it is skipped when the file is absent. Reading the real inode owner reflects the effective on-disk state, catching a chown that would let a user register an unauthorized shell.
only_if { file('/etc/shells').exist? }
describe file('/etc/shells') do
its('uid') { should eq 0 }
endHow to verify it is applied
Run stat -c '%U %u %n' /etc/shells. Expected output: root 0 /etc/shells. The numeric 0 confirms root ownership.
Inspect & investigate
Watch the file with auditctl -w /etc/shells -p wa -k shells and inspect /var/log/audit/audit.log (grep 'key="shells"'). Shell-change attempts via chsh are logged by PAM in /var/log/auth.log / journalctl.
Remediation
No automated remediation is shipped for this rule. Apply it manually with chown root /etc/shells (run as root or via sudo); the file should remain group root and mode 0644.
Pavois applies this with its own harden engine, the plan below, not a shell script:
| owner | root |
|---|---|
| path | /etc/shells |
| resource | file |
pavois harden plan localwhere the target is local, a user@host SSH alias, or a container , Docs
Impact & precautions
A non-root owner could register an arbitrary binary as a login shell, broadening interactive access. Risk of applying: none, chown root does not change which shells are listed and does not affect existing logins. Keep the file world-readable (0644) so getusershell() consumers still work.
Standards mapping
| Standard | Reference | Type | Version | Confidence |
|---|---|---|---|---|
| ANSSI BP-028 | R50 | direct | 2.0 | high |
| CIS | 7.1.9 | direct | per OS, see the benchmark table | high |
| NIST | AC-3, MP-2 | supporting | 800-53 Rev 5 · 800-171 Rev 2 (pinned) | medium |
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.