Debian GNU/Linux · Accounts & authentication

Prevent reuse of recent passwords

When it fails: Users can set a password they used before. Users forced to change a password can switch back to the old one, which may already be known to an attacker.

CB-DEB-AUTH-012lowactiveautomatedautomated fixprofile core

As released in v0.1.1 beta · pre-release. Current state.

Description

pam_pwhistory (in libpam-modules) keeps the hashes of each user's last passwords in /etc/security/opasswd and refuses a new password that matches one of the last remember. Debian ships the module but does not enable it; a pam-auth-update profile adds it to the password stack, after the quality check and before pam_unix.

Rationale

When a password is changed after a suspected compromise, going back to the previous one undoes the change. Remembering recent passwords also stops users from cycling between two values.

Impact

Users cannot reuse their last {{ remember }} passwords. The history file grows by one hash per user and change.

Setting

Location/usr/share/pam-configs/cirsec_pwhistory
DefaultNot enabled
Recommendedremember={{ remember }}, enforce_for_root, use_authtok

Parameters

ParameterCoreServerServer hardenedDesktopDesktop hardenedBounds
rememberinteger. Number of previous passwords that cannot be reused.24242424245 to 400

The value used is your override (tailoring file), else the profile's, else the one of the profile it extends, else the default. Bounds limit what an override may set.

Audit

/etc/pam.d/common-password must contain a pam_pwhistory.so line with remember= of at least {{ remember }}, enforce_for_root and use_authtok, placed before pam_unix.so.

Automated: every check must pass. Scanners report each check by its id.

module

pam_pwhistory line and its options in common-password.

script: |
  l=$(grep -E '^[[:space:]]*password[[:space:]].*pam_pwhistory\.so' /etc/pam.d/common-password) \
    || { echo "pam_pwhistory not enabled"; exit 1; }
  echo "$l"
  r=$(printf '%s\n' "$l" | sed -n 's/.*remember=\([0-9]*\).*/\1/p')
  [ "${r:-0}" -ge "$CB_REMEMBER" ] && printf '%s\n' "$l" | grep -q enforce_for_root && printf '%s\n' "$l" | grep -q use_authtok

Remediation

  1. Create /usr/share/pam-configs/cirsec_pwhistory:
    Name: CIRSEC - password history (pam_pwhistory)
    Default: yes
    Priority: 1000
    Password-Type: Primary
    Password:
            requisite       pam_pwhistory.so remember={{ remember }} enforce_for_root try_first_pass use_authtok
    
  2. Run pam-auth-update --enable cirsec_pwhistory.
Restartnone
Disruptionlow

Rollback

Run pam-auth-update --remove cirsec_pwhistory and delete the profile file.

configure

p=/usr/share/pam-configs/cirsec_pwhistory
printf '%s\n' 'Name: CIRSEC - password history (pam_pwhistory)' 'Default: yes' 'Priority: 1000' \
  'Password-Type: Primary' 'Password:' \
  "	requisite	pam_pwhistory.so remember=$CB_REMEMBER enforce_for_root try_first_pass use_authtok" >"$p"
cb_backup /etc/pam.d/common-password
DEBIAN_FRONTEND=noninteractive pam-auth-update --enable cirsec_pwhistory

Handwritten code reads parameters from CB_<NAME> environment variables. Each release turns these fixes into remediate.sh and an Ansible role per profile: dry run by default, a fix runs only when its check fails.

References

Mappings

FrameworkIDRelation
NIST SP 800-53 Rev. 55.1.1IA-5(1)partial

How this control relates to the other framework's: equivalent, stricter, looser, partial or related.

Threats mitigated

People and lifecycle

Authors
Verified2026-10-18 by Sn0wAlice on 12, Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. Reuse of the last password rejected with pamtester.
Verified2026-10-18 by Sn0wAlice on 13, Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. Reuse of the last password rejected with pamtester.
Introduced inv0.1.0
Created, updated2026-10-18, 2026-10-18
Translationsfr