Description
pam_unix checks local passwords against /etc/shadow. Two options matter here:
nulloklets accounts with an empty password field authenticate with no password. Debian sets it in the defaultunixprofile;- the hashing method used when a password is changed (
yescrypton Debian 12 and 13, orsha512). Older methods (md5,bigcrypt, DES) are fast to crack.
The packaged unix profile is replaced by a copy without nullok, so package upgrades do not
bring the option back. Passwords keep their current hash until they are changed.
Rationale
An empty password field, created by mistake or by a tool, becomes an open account as long as
nullok is present. A weak hashing method lets an attacker who copies /etc/shadow recover
passwords quickly.
Impact
Accounts with an empty password can no longer log in with a password. Give them a password, or
lock them with passwd -l.
Setting
| Location | /usr/share/pam-configs/cirsec_unix |
| Default | nullok, yescrypt |
| Recommended | No nullok, yescrypt or sha512 |
Audit
- No
pam_unix.soline in/etc/pam.d/common-author/etc/pam.d/common-passwordcontainsnullok. - The
pam_unix.soline of/etc/pam.d/common-passwordcontainsyescryptorsha512.
Automated: every check must pass. Scanners report each check by its id.
no-nullok-auth
path: /etc/pam.d/common-auth
pattern: pam_unix\.so.*\bnullok\b
expect: no_match
no-nullok-password
path: /etc/pam.d/common-password
pattern: pam_unix\.so.*\bnullok\b
expect: no_match
strong-hash
path: /etc/pam.d/common-password
pattern: ^\s*password\s+.*pam_unix\.so.*\b(yescrypt|sha512)\b
Remediation
- Lock or set a password for every account with an empty field:
awk -F: '$2==""' /etc/shadow. - Copy
/usr/share/pam-configs/unixto/usr/share/pam-configs/cirsec_unix, remove everynullok, changeName:and make sure thePassword:lines carryyescrypt. - Run
pam-auth-update --enable cirsec_unix --disable unix. - Check that a new login still works before closing your session.
| Restart | none |
| Disruption | low |
| Lockout risk | yes: can cut off administrative access. Off by default in generated scripts and playbooks, opt in through a tailoring file. |
Rollback
Run pam-auth-update --enable unix --remove cirsec_unix and delete the profile file.
profile
p=/usr/share/pam-configs/cirsec_unix
sed -e 's/^Name: .*/Name: CIRSEC - Unix authentication without nullok/' \
-e 's/[[:space:]]nullok\b//g' /usr/share/pam-configs/unix >"$p"
grep -q yescrypt "$p" || grep -q sha512 "$p" || sed -i 's/\(pam_unix\.so obscure\)/\1 yescrypt/' "$p"
for f in /etc/pam.d/common-auth /etc/pam.d/common-password /etc/pam.d/common-account /etc/pam.d/common-session; do cb_backup "$f"; done
DEBIAN_FRONTEND=noninteractive pam-auth-update --enable cirsec_unix --disable unix
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_unix(8), Debian manual pages Debian, vendor-doc, accessed 2026-10-18
- pam-auth-update(8), Debian manual pages Debian, vendor-doc, accessed 2026-10-18
- ANSSI-BP-028 v2.0 - Recommandations de configuration d'un système GNU/Linux (R68) ANSSI, guide, accessed 2026-10-18
Mappings
| Framework | ID | Relation | Note |
|---|---|---|---|
| ANSSI-BP-028 - Recommandations de configuration d'un système GNU/Linux2.0 | R68 | partial | R68 is about protecting stored passwords; this control covers the hashing method. |
| 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
People and lifecycle
| Authors |
|
| Verified | 2026-10-18 by Sn0wAlice on 12, Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64. nullok removed through the cirsec_unix profile; login with password still works (pamtester). |
| Verified | 2026-10-18 by Sn0wAlice on 13, Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64. nullok removed through the cirsec_unix profile; login with password still works (pamtester). |
| Introduced in | v0.1.0 |
| Created, updated | 2026-10-18, 2026-10-18 |
| Translations | fr |