Verify /boot/grub2/user.cfg Permissions
Ensures the GRUB password file /boot/grub2/user.cfg is owned by root and is not readable, writable or executable by group or other, with no setuid/setgid/sticky bits, so only root can read or modify the boot password hash.
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 boot password as a PBKDF2 hash (GRUB2_PASSWORD=grub.pbkdf2...). If it is readable by group or other, that hash can be extracted and cracked offline, defeating the boot-time password that protects single-user mode and kernel-argument edits. If it is writable by group or other, an attacker can replace the hash with one they know and gain interactive access to the boot loader. Restricting access to root keeps the boot password secret and tamper-proof.
What Pavois checks
Pavois reads the live inode with file('/boot/grub2/user.cfg') and asserts no group/other access and no special mode bits, gated by only_if to skip when the file is absent (it only exists once a GRUB password has been set). Inspecting effective on-disk permissions catches drift introduced when the file is regenerated or restored from backup, which can reset the mode, rather than assuming the value from documentation.
only_if { file('/boot/grub2/user.cfg').exist? }
describe file('/boot/grub2/user.cfg') do
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 '%a %U %G' /boot/grub2/user.cfg. Expected: mode 600 (or stricter, e.g. 700), owner root, group root, no read/write/execute for group or other, and no setuid/setgid/sticky bit.
Inspect & investigate
No service log applies; inspect with stat /boot/grub2/user.cfg or ls -l /boot/grub2/user.cfg. To detect tampering, add an auditd watch (auditctl -w /boot/grub2/user.cfg -p wa -k grub) and grep /var/log/audit/audit.log for key="grub".
Remediation
No automated remediation is defined, so apply it manually: chown root:root /boot/grub2/user.cfg && chmod 600 /boot/grub2/user.cfg. Re-run the scan to confirm the rule passes.
Pavois applies this with its own harden engine, the plan below, not a shell script:
| mode | 0700 |
|---|---|
| path | /boot/grub2/user.cfg |
| resource | file |
pavois harden plan localwhere the target is local, a user@host SSH alias, or a container , Docs
Impact & precautions
Risk if left misconfigured: a readable user.cfg exposes the GRUB password hash for offline cracking; a writable one lets an attacker swap in a known password and own the boot loader. Precautions: tightening to root:root 600 is safe, GRUB reads this file during early boot from firmware, not as a normal user, so the boot password keeps working. Re-verify after regenerating the GRUB configuration, which may reset the mode.
Standards mapping
| Standard | Reference | Type | Version | Confidence |
|---|---|---|---|---|
| ANSSI BP-028 | R29 | direct | 2.0 | high |
| NIST | 3.4.5 | supporting | 800-53 Rev 5 · 800-171 Rev 2 (pinned) | medium |
| CIS | 1.4.2 | direct | per OS, see the benchmark table | high |
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.