Remediation Guides

How to Fix “Ensure lockout for failed password attempts is configured” with pam_faillock

26 September 2026 8 min read

Ensure lockout for failed password attempts is configured is a CIS Linux benchmark check that fails when PAM does not lock an account after repeated wrong passwords. To fix it, enable pam_faillock (with authselect enable-feature with-faillock on RHEL, or in /etc/pam.d/common-auth on Debian and Ubuntu), set deny = 5 and unlock_time = 900 in /etc/security/faillock.conf, then rescan.

What the scanner is actually detecting

This finding comes from Tenable’s CIS Linux audit files, which Nessus runs as a credentialed Unix compliance check. It is a configuration check, so there is no CVE and no package to update. The item number depends on the benchmark: 4.4.2 in the CIS Debian Linux 10 v2.0.0 audit, 5.3.2 in CIS Ubuntu 20.04 LTS v1.0.0, 5.4.2 in CIS Debian Linux 11 v1.0.0 and 5.5.2 in CIS Red Hat EL8 v2.0.0, all titled Ensure lockout for failed password attempts is configured. Tenable often splits one control into sub-checks with a suffix, such as 5.5.2 … – >= 8.2 deny or 5.3.2 … – auth pam_tally2.so, so a single host can show several failed rows for one control.

What the check reads differs by platform:

  • RHEL 8.2 and later: /etc/security/faillock.conf. The RHEL 8 item asks for deny of 5 or less and unlock_time of 0 (never) or at least 900 seconds. A companion item, Ensure authselect includes with-faillock (5.3.3 in the CIS CentOS 8 v1.0.0 audit, for example), checks that the module is actually in the PAM stack.
  • Debian 11: the pam_faillock lines in /etc/pam.d/common-auth and /etc/pam.d/common-account, plus faillock.conf.
  • Ubuntu 20.04 and older Debian audits: a pam_tally2.so line with deny and unlock_time options.

Newer CIS releases split the control into several items, for example 5.3.2.2 Ensure pam_faillock module is enabled in the Ubuntu 24.04 benchmark, but the fix is the same.

Real-world risk

Without a lockout, online password guessing against PAM services that ask for a password (SSH password logins, the console, su) is limited only by per-connection controls such as sshd’s MaxAuthTries and the delay after a failed attempt. An attacker can simply reconnect and keep guessing. A lockout caps the number of guesses per account in each interval, which is why CIS lists it as a brute-force mitigation.

Keep it in proportion. This is a hardening control, not an exploitable flaw. On a host where SSH accepts keys only and there are no password-based remote logins, the practical gain is small. The lockout also creates a new lever: anyone who knows a username can lock that account on purpose, and the faillock.conf manual warns that permanent lockouts invite denial of service. By default root is never locked.

How to confirm it on the host

On RHEL 8/9 and rebuilds:

sudo authselect current
grep -n pam_faillock /etc/pam.d/system-auth /etc/pam.d/password-auth
grep -Ev '^s*(#|$)' /etc/security/faillock.conf
grep -En 'pam_faillock.so.*(deny|unlock_time)=' /etc/pam.d/*

If with-faillock is missing from the enabled features and there are no pam_faillock lines, nothing is counting failures. If the lines exist but faillock.conf has no active settings, the built-in defaults apply: deny = 3, fail_interval = 900 and unlock_time = 600. That still fails the RHEL item, because 600 is below 900. The last command finds options set directly on a PAM line, which override the file.

On Debian and Ubuntu, first check which module your PAM version ships:

dpkg -L libpam-modules | grep -E 'pam_(faillock|tally2).so$'
grep -En 'pam_(faillock|tally2)' /etc/pam.d/common-auth /etc/pam.d/common-account
grep -Ev '^s*(#|$)' /etc/security/faillock.conf

Upstream Linux-PAM added pam_faillock in release 1.4.0 and removed pam_tally2 in 1.5.0, so current releases have only pam_faillock. To see an account’s recorded failures, run sudo faillock --user alice (or sudo pam_tally2 --user alice on older systems).

How to fix it

Before touching PAM on any platform, keep a second root session open and do not close it until a fresh login works. A broken auth stack can lock out every user, root included.

RHEL 8.2 and later, RHEL 9 and rebuilds (authselect)

sudo authselect current
sudo authselect enable-feature with-faillock
sudo authselect apply-changes

Then set the policy in /etc/security/faillock.conf (the file uses name = value lines):

deny = 5
unlock_time = 900

fail_interval already defaults to 900 seconds. If the earlier grep found deny= or unlock_time= on a pam_faillock line, remove those options from the custom authselect profile under /etc/authselect/custom/ and run sudo authselect apply-changes, so the file is the single source of truth. There is no daemon to restart.

If authselect current reports that no existing configuration was detected, the PAM files were written by hand. authselect select sssd with-faillock --force takes over management and, per the authselect manual, backs up the existing files first, but it replaces any manual PAM customizations, so review them before running it. On RHEL 8.0 and 8.1, which predate faillock.conf support, the options have to go on the pam_faillock lines of a custom profile.

Debian 11 and later, Ubuntu 22.04 and later (pam_faillock)

Back up the files first:

sudo mkdir -p /root/pam-backup
sudo cp -a /etc/pam.d/common-auth /etc/pam.d/common-account /root/pam-backup/

Edit the primary block of /etc/pam.d/common-auth so the pam_faillock lines surround pam_unix.so, in this exact order (this is the layout from the CIS Debian 11 remediation):

auth    required                     pam_faillock.so preauth
auth    [success=1 default=ignore]   pam_unix.so nullok
auth    [default=die]                pam_faillock.so authfail
auth    sufficient                   pam_faillock.so authsucc
auth    requisite                    pam_deny.so
auth    required                     pam_permit.so

success=1 tells PAM to skip one line on a correct password, so a success jumps over authfail to authsucc, which clears the counter. If your file has other modules such as pam_sss.so or pam_krb5.so in this block, the success=N jump counts must be recalculated, or logins will fail or succeed incorrectly. Then add this line at the end of /etc/pam.d/common-account:

account required pam_faillock.so

Finally set deny and unlock_time in /etc/security/faillock.conf as shown above. The Debian 11 item gives deny = 4, fail_interval = 900 and unlock_time = 600 only as an example to adjust to site policy. Note that pam-auth-update treats files with added modules as locally modified and stops changing them, unless someone later runs it with --force, which would drop your lines.

Ubuntu 20.04 and Debian 10 (pam_tally2)

The CIS Ubuntu 20.04 item asks for this line in /etc/pam.d/common-auth, placed before the pam_unix.so line:

auth required pam_tally2.so onerr=fail audit silent deny=5 unlock_time=900

and this line in /etc/pam.d/common-account, which Tenable notes is needed for the counter to reset when using sudo:

account required pam_tally2.so

Tenable also warns that the audit keyword may log credentials when a user types a password into the username prompt. Unlock with sudo pam_tally2 --user alice --reset. Both releases are past the end of standard support, and upgrading moves you to pam_faillock.

How to verify the fix and rescan

Test with a throwaway account. Run the su step from a non-root shell, because root is not asked for a password:

sudo useradd -m lockouttest
sudo passwd lockouttest
su - lockouttest            # repeat with wrong passwords past the deny count
sudo faillock --user lockouttest
sudo faillock --user lockouttest --reset
sudo userdel -r lockouttest

After enough failures, the correct password should also be refused, and faillock --user should list the failed attempts. On RHEL, authselect current should list with-faillock. Then rerun the same compliance scan, with the same audit file and credentials, against the host.

What can break and how to roll back

  • A bad PAM stack. Wrong ordering or jump counts can block all logins. This is why the second root session matters.
  • Service and scan accounts. An automation or scanner account with a stale password now locks itself out on every run. If your compliance scans use a password-based account, recheck how you are setting up a credentialed Linux scan over SSH with sudo before rolling this out.
  • Deliberate lockouts. Anyone who can reach a password prompt can lock a known username. unlock_time = 0 makes that permanent until an admin resets it.
  • Directory users. For SSSD, AD or IdM accounts, the local_users_only option limits tracking to /etc/passwd users and avoids a double lockout alongside the directory’s own policy.

To roll back on RHEL, run sudo authselect disable-feature with-faillock, or list and restore an authselect backup with authselect backup-list and authselect backup-restore NAME. On Debian and Ubuntu, copy the saved files back:

sudo cp -a /root/pam-backup/common-auth /root/pam-backup/common-account /etc/pam.d/

Common false positive reasons

  • Options on the PAM line only. The RHEL 8.2+ check reads faillock.conf. Lockout may work with deny=5 on the module line while the audit still fails. Move the values into the file.
  • Wrong audit file. A pam_tally2-based audit run against a release that ships only pam_faillock cannot pass. Tenable has marked the Ubuntu 20.04 v1.0.0 audit as deprecated in favor of v1.1.0, so use the audit that matches the OS release.
  • Stale results. The report predates the change, or the rescan ran without credentials.

Some findings look false but are real: faillock.conf is fully configured but with-faillock was never enabled, so the module is not in the stack, or unlock_time was left at the 600 second default.

FAQ

Does pam_faillock lock the root account?

Not by default. The even_deny_root and root_unlock_time options in faillock.conf change that, and some benchmarks check them in a separate item.

Does it stop SSH key logins for a locked user?

No. The sshd_config manual says UsePAM enables PAM authentication for password and keyboard-interactive logins, with only account and session processing for other methods. The lock is enforced in the auth stack, so public key logins are neither counted nor blocked.

Does a reboot unlock accounts?

Usually yes. Failure records live in /var/run/faillock, which is normally cleared at boot. Set dir= in faillock.conf for persistent records.

How do I unlock a user right now?

Run sudo faillock --user alice --reset, which clears that user’s failure records.

Tracking this finding across many hosts

A PAM change is easy on one server and risky across a fleet, so the harder part is knowing which hosts are still open. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners (Nessus results arrive as an uploaded .nessus export) and merges duplicates reported by the same scanner. Its AI can draft host-specific remediation scripts that run only after human approval, deployed by SITEY agents on Linux endpoints, and SITEY re-tests afterward to verify closure.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing