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.
Ubuntu 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.
The options are set on the pam_pwhistory.so line, which works on every Ubuntu release.
/etc/security/pwhistory.conf only exists from Ubuntu 24.04 (PAM 1.5); options on the module
line take precedence over it. The history must be kept by pam_pwhistory only: the older
remember= option of pam_unix stores it in a different way and must not be used.
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 |
| Default | Not enabled |
| Recommended | remember={{ remember }}, enforce_for_root, use_authtok |
Parameters
| Parameter | Core | Server | Server hardened | Desktop | Desktop hardened | Bounds |
|---|---|---|---|---|---|---|
rememberinteger. Number of previous passwords that cannot be reused. | 24 | 24 | 24 | 24 | 24 | 5 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.
No pam_unix.so line of /etc/pam.d/common-* has a remember= option.
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
no-unix-remember
pam_unix does not keep its own password history.
path: /etc/pam.d/common-*
pattern: ^[^#]*pam_unix\.so.*\sremember=
expect: no_match
Remediation
- 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 - Run
pam-auth-update --enable cirsec_pwhistory. - If a
pam_unix.soline hasremember=, remove it from thepam-auth-updateprofile that adds it (or from the file edited by hand), then runpam-auth-updateagain.
| Restart | none |
| Disruption | low |
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
- pam_pwhistory(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
- pam-auth-update(8), Ubuntu manual pages Canonical, vendor-doc, accessed 2026-10-19
Mappings
| Framework | ID | Relation |
|---|---|---|
| NIST SP 800-53 Rev. 55.1.1 | IA-5(1) | partial |
How this control relates to the other framework's: equivalent, stricter, looser, partial or related.
Threats mitigated
| Taxonomy | ID |
|---|---|
| MITRE ATT&CK | T1110 |
Related controls
- related
CB-UBU-AUTH-010Enforce password quality with pam_pwquality
People and lifecycle
| Authors |
|
| Verified | 2026-10-19 by Sn0wAlice on 20.04, Proxmox VM, Ubuntu 20.04 cloud image, kernel 5.4.0-216-generic. Reuse of the previous password rejected with pamtester; no remember on pam_unix; kept after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 22.04, Proxmox VM, Ubuntu 22.04 cloud image, kernel 5.15.0-198-generic. Reuse of the previous password rejected with pamtester; no remember on pam_unix; kept after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 24.04, Proxmox VM, Ubuntu 24.04 cloud image, kernel 6.8.0-147-generic. Reuse of the previous password rejected with pamtester; no remember on pam_unix; kept after reboot. |
| Verified | 2026-10-19 by Sn0wAlice on 26.04, Proxmox VM, Ubuntu 26.04 cloud image, kernel 7.0.0-38-generic. Reuse of the previous password rejected with pamtester; no remember on pam_unix; kept after reboot. |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-19, 2026-10-19 |
| Translations | fr |