Verify /boot/grub2/user.cfg Permissions
Ensures /boot/grub2/user.cfg (the GRUB superuser password file) is readable and writable only by root, with no execute/setuid/setgid/sticky bits.
Checked against the content of a persistent configuration file, the source of truth that survives reboots.
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
/boot/grub2/user.cfg stores the GRUB bootloader superuser password hash (PBKDF2). If group or other can read it, an attacker can crack the hash offline and gain the GRUB superuser password, letting them edit boot entries, drop to a root shell via init=/bin/bash, or disable security at boot, a full bypass of OS-level access controls. If the file is writable by a non-root user, they can replace or remove the password protection entirely. Only root should read or modify it.
What Pavois checks
Pavois reads the effective inode mode of /boot/grub2/user.cfg and asserts no read/write for group or other and no special bits. Checking the live file (rather than assuming the generator wrote it correctly) catches cases where the file was regenerated, copied, or chmod-ed after creation and silently became group/world-readable.
only_if { file('/boot/grub/user.cfg').exist? }
describe file('/boot/grub/user.cfg') do
it { should_not be_executable.by('owner') }
it { should_not be_setuid }
it { should_not be_executable.by('group') }
it { should_not be_writable.by('group') }
it { should_not be_readable.by('group') }
it { should_not be_setgid }
it { should_not be_executable.by('other') }
it { should_not be_writable.by('other') }
it { should_not be_readable.by('other') }
it { should_not be_sticky }
endHow to verify it is applied
Run stat -c '%U %G %a' /boot/grub2/user.cfg. Expected: owner/group root with mode 600 (or 0600), readable/writable by root only, no bits for group/other.
Inspect & investigate
There is no runtime log for this file. Integrity drift can be detected with rpm -Vf /boot/grub2/user.cfg (RHEL/Alma/Fedora). GRUB regeneration that may rewrite it is triggered by grub2-mkconfig; review its output and re-check the mode afterward.
Remediation
No automated remediation ships for this rule. Tighten the file manually: chown root:root /boot/grub2/user.cfg && chmod 600 /boot/grub2/user.cfg.
Pavois applies this with its own harden engine, the plan below, not a shell script:
| mode | 0600 |
|---|---|
| path | /boot/grub/user.cfg |
| resource | file |
pavois harden plan localwhere the target is local, a user@host SSH alias, or a container , Docs
Impact & precautions
A readable user.cfg leaks the GRUB superuser hash (offline crackable, leading to boot-time root access); a writable one lets an attacker disable boot password protection. Setting it to 0600 root:root is safe and matches the GRUB default. Precaution: do not delete or empty the file, that removes GRUB password protection. Re-run grub2-mkconfig only when needed, since regeneration can reset the mode.
Standards mapping
| Standard | Reference | Type | Version | Confidence |
|---|---|---|---|---|
| ANSSI BP-028 | R29 | direct | 2.0 | high |
| CIS | 2.2.6, 1.4.2 | direct | per OS, see the benchmark table | high |
| NIST | 3.4.5, AC-6(1), CM-6(a) | supporting | 800-53 Rev 5 · 800-171 Rev 2 (pinned) | medium |
| PCI DSS | 2.2.6 | supporting | 4.0.1 | 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.