Handbook sections▾
Foundations
Understanding the threats to a Linux hostWhy we hardenThe defense principles behind every ruleEffective configuration: the truth no file holdsThe standards Pavois maps toSOCLE control ID modelEvidence & exportsHow the A-E grade is computedWhat a PASS proves: the qualified verdictTrust model for the evidence bundleIs SOCLE just your own norm? (governance & the circularity question)What Pavois covers, and what it doesn'tDomains
Hardening SSHHardening PAMMandatory Access Control (SELinux / AppArmor)Hardening the host firewallHardening sudoFile Permissions & OwnershipMount & filesystem hardeningHardening kernel modulesHardening the kernel & network with sysctlAudit logging with auditdHardening logging with journald and rsyslogHardening systemd servicesPackage hygieneHardening the bootloader (GRUB)Synchronizing timeLogin banners and MOTDControlling cron and at accessHardening the GNOME desktop (dconf)Tooling
Undo a hardening run: restore pointsOperating Pavois: privileges, air-gap, timing, exceptionsRun Pavois in CI (GitHub Actions)Feature status: delivered, partial, roadmapGovernance: licence, versioning, provenance, securityFile Permissions & Ownership
Last reviewed
Sensitive files like /etc/shadow, SSH keys and cron jobs are only as safe as their mode bits. Tighten permissions, set a strict UMASK, kill world-writable files and review SUID/SGID so a low-privilege account can't read secrets or escalate.
The threat: a loose mode bit turns a foothold into a breach
Discretionary access control is the last line of defense when an attacker already has an account on the box. A loose permission turns a foothold into a breach: a world-readable /etc/shadow hands over every password hash for offline cracking; a group-writable /etc/passwd, /etc/sudoers or /etc/crontab lets an unprivileged user rewrite identity, sudo policy or a root cron job and escalate at will. World-writable files (-rw-rw-rw-) in shared paths like /tmp are a classic vector for symlink and config-injection attacks. SUID/SGID binaries run with the owner's privileges regardless of who launches them: a single misplaced setuid-root binary is a direct path to root. And SSH host keys or private keys readable by other undermine the whole trust chain.
Why harden it
Permissions are cheap to get wrong and catastrophic when wrong. There is no exploit to write: the attacker simply reads the file or runs the binary the kernel already lets them touch. Hardening this domain means that even after an account is compromised, the secrets stay unreadable, the privilege-policy files stay untouchable, and there are no surprise paths to root, shrinking the blast radius of every other failure.
Defense principles applied
- Least privilege: secrets get the minimum mode.
/etc/shadowand/etc/gshadowunreadable to group/other (0000or0640),/etc/sudoersroot-only (0440),/etc/passwd//etc/group0644, audit logs0640or stricter. - Attack-surface reduction: no unauthorized world-writable files; no stray SUID/SGID bits where they aren't needed.
- Integrity over confidentiality where it matters:
/etc/passwdmust stay world-readable to function, so the rule is that it is not writable by group/other; the credential files get both. - Accountability: log files under
/var/logare locked down so an attacker can't read or tamper with the trail. - Fine-grained control with ACLs: when owner/group/other modes are too coarse, POSIX ACLs (
setfacl/getfacl) grant a specific user exactly the access needed.
Set a strict default with UMASK 027
Every file a process creates inherits a mode masked by UMASK. The permissive default 022 makes new files world-readable; 027 removes all access for other (and write for group), so a freshly written log, key or config is private by default. Set it in /etc/login.defs (UMASK 027), reinforce it through PAM (pam_umask), and in /etc/profile//etc/bashrc. This is a system-wide safety net: it fixes the files you forget, not just the ones you chmod.
Hunt the dangerous files
# World-writable files (and dirs missing the sticky bit)
find / -xdev -type f -perm -0002 -ls
find / -xdev -type d -perm -0002 ! -perm -1000 -ls
# SUID / SGID inventory: review against a known baseline
find / -xdev \( -perm -4000 -o -perm -2000 \) -type f -ls
# Unowned files: a deleted user's UID still owns these
find / -xdev \( -nouser -o -nogroup \) -lsAn unowned file is dangerous because a new account reusing that UID silently inherits ownership. A surprise SUID binary is the shortest escalation path; compare the inventory to the distro's expected set and chmod u-s anything unexpected.
What Pavois audits: the actual mode on the target
Pavois's File permissions rules resolve the actual mode and ownership on the target (via CINC's file resource), not what a template claims. It checks credential/identity files (/etc/shadow, /etc/gshadow carry no access; /etc/passwd, /etc/group are not writable by group/other, plus their .bak), privilege policy (/etc/sudoers, /etc/sudoers.d/), the full cron/at surface, SSH material (/etc/ssh, host keys, *.pub, sshd_config.d/), bootloader files, and the log trail. Every rule asserts the setuid/setgid/sticky bits are off where they must be, and a dedicated world-writable canary confirms shared paths like /tmp are not writable by other. These map to CIS file-permission sections and ANSSI BP-028 R29/R50.
Pitfalls
- A blanket
chmod -Rbreaks things: tightening/etcrecursively can strip execute bits off directories. Target specific files. - Removing a legitimate SUID bit breaks a tool (
passwd,sudo,pinghistorically): review, don't strip blindly. - UMASK in one place isn't enough: a login shell, a cron job and a systemd service can each have a different umask; set it in
login.defsand PAM. /etc/passwdat0600locks out name resolution: it must stay0644(readable), only unwritable by others.
FAQ
Why 0000/0640 on /etc/shadow and not 0644? Because it holds password hashes; only root (and the shadow group on some distros) needs them. World-readable shadow is offline cracking handed over.
UMASK 022 or 027? 027 for a hardened host: new files are private to owner and group, denied to others. 022 leaves them world-readable.
How do I find escalation paths I missed? Inventory SUID/SGID (find -perm -4000), world-writable files, and unowned files; compare against the distro baseline and your expectations.