Verify the UEFI Boot Loader grub.cfg Permissions
Ensures the UEFI bootloader file /boot/grub2/grub.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 boot parameters.
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/grub.cfg defines the boot menu, kernel command line and boot parameters. If it is writable by group or other, an attacker can alter kernel arguments, e.g. add init=/bin/bash, disable security mitigations, or bypass an enforced boot password, and gain control of the system at boot. If it is readable by group/other, any hashed boot password it contains is exposed for offline cracking. Restricting access to root ensures only the administrator can read or change critical boot settings.
What Pavois checks
Pavois reads the live inode with file('/boot/grub2/grub.cfg') and asserts no group/other access and no special mode bits, gated by only_if to skip when the file is absent (e.g. on BIOS systems or distros using /boot/efi/.../grub.cfg). Inspecting effective on-disk permissions catches drift introduced when the file is regenerated by grub2-mkconfig, a kernel update, or a backup restore, which can reset the mode, rather than assuming the value from documentation.
only_if { file('/boot/grub2/grub.cfg').exist? }
describe file('/boot/grub2/grub.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/grub.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/grub.cfg or ls -l /boot/grub2/grub.cfg. To detect tampering, add an auditd watch (auditctl -w /boot/grub2/grub.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/grub.cfg && chmod 600 /boot/grub2/grub.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/grub.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 group/other-writable grub.cfg lets a local attacker rewrite the kernel command line and take over the system at next boot; a readable one leaks the GRUB password hash. Precautions: tightening to root:root 600 is safe, GRUB reads the file from firmware/early boot, not as a normal user, so boot is unaffected. Note that grub2-mkconfig may rewrite the file and can reset its mode, so re-verify after any kernel or bootloader update.
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.