“Ensure bootloader password is set” is a CIS benchmark check that fails when GRUB 2 lets anyone at the console edit boot entries or open the GRUB shell. To fix it, run grub2-setpassword on RHEL-family systems, or on Debian and Ubuntu add set superusers and password_pbkdf2 lines to /etc/grub.d/40_custom and run update-grub.
The command takes a minute. The planning is about reboots: on Debian and Ubuntu, a superuser password without –unrestricted on the normal entries makes every boot stop at a login prompt, a bad surprise on a remote server after patching.
What the scanner is actually detecting
This is a configuration item from the CIS Linux audit files that Tenable runs during an authenticated compliance scan. It has no CVE; it reports PASSED or FAILED based on whether GRUB has a superuser with a PBKDF2 password hash. Item numbers differ between benchmarks, so search your report by title:
| Tenable audit (CIS benchmark) | Item title |
|---|---|
| CIS Rocky Linux 9 v2.0.0 L1 Server | 1.4.1 Ensure bootloader password is set |
| CIS Red Hat Enterprise Linux 9 v2.0.0 L1 Server | 1.4.1 Ensure bootloader password is set |
| CIS Oracle Linux 7 v4.0.0 L1 Server | 1.3.1 Ensure bootloader password is set |
| CIS Debian Linux 12 v1.0.1 L1 Server | 1.4.1 Ensure bootloader password is set |
| CIS Ubuntu Linux 22.04 LTS Server L1 v1.0.0 | 1.4.1 Ensure bootloader password is set – ‘set superusers’ (plus a second item ending in ‘passwd_pbkdf2’) |
On RHEL-family audits the check runs a command that looks for the hash written by grub2-setpassword. On Ubuntu the audit reads the generated /boot/grub/grub.cfg and splits the item in two: one for the set superusers line and one for the password_pbkdf2 line. A DISA STIG item on RHEL 9, RHEL-09-212010 (“RHEL 9 must require a boot loader superuser password”), has the same fix.
A companion item (1.4.2 “Ensure access to bootloader config is configured” on Rocky Linux 9 v2.0.0) checks permissions on the bootloader files. Fix both, because a hash in a world-readable file can be cracked offline.
Real-world risk, stated honestly
Without a GRUB password, anyone who reaches the boot menu can press e and add kernel parameters. Red Hat documents exactly this path for resetting a lost root password with rd.break, and the CIS rationale mentions turning off SELinux or AppArmor at boot. Either way, no Linux password is needed.
The exposure is limited to people who can reach the console:
- Physical access to the machine.
- Out-of-band consoles such as a BMC remote KVM, a hypervisor console, or a cloud serial console.
It is not exploitable over the network, and it has hard limits. The GNU GRUB manual notes that someone with physical access has other ways in, such as booting other media or pulling the disk. A GRUB password closes the easiest path; pair it with a firmware (BIOS/UEFI) password, a locked boot order and disk encryption. It adds little on a VM whose hypervisor admins can mount the disk anyway.
How to confirm it on the host
Run these as root; on a hardened host these files are root-only.
RHEL, Rocky Linux, AlmaLinux, Oracle Linux and CentOS:
# BIOS or UEFI?
[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS
# Is a password hash present? (prints only the prefix, not the hash)
sudo find /boot -name user.cfg -exec grep -Ho '^GRUB2_PASSWORD=grub.pbkdf2.sha512' {} ;
# Does grub.cfg load user.cfg and define a superuser?
sudo grep -nE 'user.cfg|superusers' /boot/grub2/grub.cfg
No output from the find command means no password is set. On RHEL 9 family systems the real configuration is /boot/grub2/grub.cfg on both BIOS and UEFI; on RHEL 8 family and older UEFI installs, grub.cfg lives in the EFI vendor directory (for example /boot/efi/EFI/redhat), and user.cfg must sit next to it.
Debian and Ubuntu:
sudo grep -nE '^s*(set superusers|export superusers|password_pbkdf2)' /boot/grub/grub.cfg
sudo grep -nE 'superusers|password' /etc/grub.d/*
If the first command prints nothing, the check fails. If only the second finds lines, someone edited /etc/grub.d but never ran update-grub.
How to fix it
Choose a GRUB password that differs from every Linux account password, and store it in your vault first.
RHEL family: grub2-setpassword
sudo grub2-setpassword
Enter password:
Confirm password:
This writes a GRUB2_PASSWORD=grub.pbkdf2.sha512… line to user.cfg in the GRUB directory (default /boot/grub2). The 01_users block in grub.cfg reads that file and makes a GRUB superuser named root. That is a GRUB account, separate from the Linux root user. If grub.cfg has no reference to user.cfg, regenerate it:
# RHEL 9 family, BIOS and UEFI; RHEL 8 family on BIOS
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
On RHEL 8 family UEFI systems, check that user.cfg landed in the same directory as the grub.cfg the firmware loads. If it did not, rerun the tool with -o, which the man page defines as the output directory for user.cfg:
sudo grub2-setpassword -o /boot/efi/EFI/redhat # use your vendor directory
Red Hat is explicit that grub2-setpassword protects entries from modification, not from booting. On RHEL 8 and later, boot entries carry grub_arg –unrestricted in their files under /boot/loader/entries (on RHEL 7, the flag is on the menuentry lines in grub.cfg), so unattended reboots keep working.
Debian and Ubuntu: grub-mkpasswd-pbkdf2 and 40_custom
Generate the hash:
grub-mkpasswd-pbkdf2
Enter password:
Reenter password:
PBKDF2 hash of your password is grub.pbkdf2.sha512.10000.<salt>.<hash>
The default is 10,000 PBKDF2 iterations; -c raises it. Copy the whole string starting with grub.pbkdf2.sha512. Then append the superuser definition to /etc/grub.d/40_custom, keeping backups outside /etc/grub.d because every executable file in that directory is run by update-grub:
sudo cp -a /etc/grub.d/40_custom /root/40_custom.bak
sudo tee -a /etc/grub.d/40_custom > /dev/null <<'EOF'
set superusers="grubadmin"
export superusers
password_pbkdf2 grubadmin grub.pbkdf2.sha512.10000.PASTE_THE_REST_HERE
EOF
The heredoc only writes the file. Do not put cat <<EOF lines inside 40_custom: its exec tail header already copies everything below it into grub.cfg. export superusers follows the GRUB manual note that the variable must be exported to protect submenus too. The user name exists only in GRUB. CIS says not to use 00_header, which package updates can overwrite.
Next, decide how normal boots behave. GRUB lets only superusers run entries that have neither –users nor –unrestricted. On a server that must reboot unattended, add –unrestricted to the CLASS line in /etc/grub.d/10_linux, as the CIS remediation describes:
sudo cp -a /etc/grub.d/10_linux /root/10_linux.bak
sudo grep -n '^CLASS=' /etc/grub.d/10_linux
# edit that line so it ends with --unrestricted, for example:
# CLASS="--class gnu-linux --class gnu --class os --unrestricted"
Then regenerate the configuration (update-grub is a wrapper for grub-mkconfig -o /boot/grub/grub.cfg):
sudo update-grub
10_linux ships with the GRUB package, so recheck the CLASS line after GRUB upgrades.
How to verify the fix and rescan
# RHEL family
sudo grep -co '^GRUB2_PASSWORD=grub.pbkdf2.sha512' /boot/grub2/user.cfg # expect 1
# Debian / Ubuntu
sudo grep -nE '^s*(set superusers|password_pbkdf2)' /boot/grub/grub.cfg # expect both lines
sudo grep -c -- '--unrestricted' /boot/grub/grub.cfg # expect more than 0
sudo grub-script-check /boot/grub/grub.cfg # no output means valid syntax
Then test in a maintenance window with console access. The default entry should boot without a prompt. Pressing e or c at the menu should ask for a user name and password (root on RHEL family, your chosen name on Debian and Ubuntu). Finally, rerun the same compliance scan with the same audit file and confirm the item moves to PASSED.
What can break and how to roll back
- Stuck reboots on Debian and Ubuntu: without –unrestricted, every boot waits at a login prompt. The Ubuntu wiki warns that if the default entry is protected, Shift will not show the menu, so you cannot pick another entry.
- Slower incident recovery: editing kernel parameters now needs the GRUB password, so on-call staff must be able to get it.
- Shared hashes: a golden image with one baked-in hash gives every server the same GRUB password.
- Configuration drift: configuration management that re-renders /etc/grub.d can silently undo the change.
To roll back on RHEL family systems, move the hash file away (01_users only sets a superuser when user.cfg holds a password):
sudo mv /boot/grub2/user.cfg /root/user.cfg.bak # RHEL 8 UEFI: use the EFI vendor directory
On Debian and Ubuntu, restore the backups and regenerate:
sudo cp -a /root/40_custom.bak /etc/grub.d/40_custom
sudo cp -a /root/10_linux.bak /etc/grub.d/10_linux
sudo update-grub
If a host no longer boots unattended, boot rescue or live media, mount the root filesystem, remove the lines, and regenerate grub.cfg from a chroot.
Common false positive reasons
- The scan could not read the files. user.cfg and a hardened grub.cfg are root-only. Without working sudo elevation, the item can fail on a correct host. Our guide to configuring SSH credentials and sudo for Linux authenticated scans covers the scan account.
- The file is not where the audit looks. On RHEL 8 family UEFI hosts, both files sit in the EFI vendor directory. Check the path in the audit output first.
- update-grub was never run. The lines exist in 40_custom but not in /boot/grub/grub.cfg. This is a true positive: GRUB reads grub.cfg, not /etc/grub.d.
- A plain-text password was used. A password line instead of password_pbkdf2 fails the ‘passwd_pbkdf2’ item, and it deserves to.
- GRUB is not the bootloader. Hosts with another bootloader, or VMs that boot a kernel directly, cannot pass as written. CIS says to apply equivalent settings; record a documented exception.
FAQ
Will a GRUB password stop my server from rebooting unattended?
On RHEL family systems, no: grub2-setpassword only protects editing, because boot entries are marked unrestricted. On Debian and Ubuntu, yes, unless you add –unrestricted to the normal menu entries.
Is the GRUB user the same as the Linux root account?
No. GRUB users exist only in the boot configuration. RHEL calls its GRUB superuser root, but its password is whatever you gave grub2-setpassword.
I forgot the GRUB password. How do I reset it?
If normal entries are unrestricted, boot as usual and set a new one: rerun grub2-setpassword, or replace the hash in 40_custom and run update-grub. Otherwise use rescue media as described above.
Does this replace a BIOS/UEFI password or disk encryption?
No. It only protects the GRUB menu and shell. Someone who can boot other media or remove the disk bypasses it.
Tracking this finding across many hosts
Across a large fleet, the usual problem is drift: a rebuilt image or a configuration management run quietly drops the password. If you use SITEY, you can upload the .nessus export from the compliance scan, have its AI draft a host-specific script that runs only after a human approves it, deploy it through SITEY agents on Linux endpoints, and let SITEY re-test to confirm the finding closed. Duplicates are merged per scanner, not across scanners.
Sources
- Tenable: CIS Rocky Linux 9 v2.0.0 L1 Server, 1.4.1 Ensure bootloader password is set
- Tenable: CIS Ubuntu Linux 22.04 LTS Server L1, 1.4.1 Ensure bootloader password is set – ‘set superusers’
- GNU GRUB Manual: Authentication and authorisation in GRUB
- Red Hat: RHEL 8, Protecting GRUB with a password
- Ubuntu Community Help Wiki: Grub2/Passwords