# yaml-language-server: $schema=../../../../schema/control.schema.json id: CB-DEB-AUTH-014 title: Set password aging and hashing defaults for new accounts finding: title: New accounts get passwords that never expire and are never disabled when unused description: Accounts created with the Debian defaults keep the same password forever and stay usable after their owner left. status: active profiles: [core] risk: severity: low assessment: automated tags: [password, accounts, login-defs] description: | `/etc/login.defs` and `useradd -D` define what new local accounts get: - `PASS_MAX_DAYS`: maximum age of a password (Debian: 99999, never expires); - `PASS_MIN_DAYS`: minimum days between two changes (Debian: 0); - `PASS_WARN_AGE`: days of warning before expiry (Debian: 7); - `ENCRYPT_METHOD`: hash used by `chpasswd` and `newusers` (Debian 12: SHA512, Debian 13: YESCRYPT); - `INACTIVE` (`useradd -D`): days after password expiry before the account is disabled (Debian: never). rationale: | A password that is never renewed and an account that is never disabled let a leaked password, or a departed user, keep access indefinitely. A minimum age stops users from cycling through the history to get their old password back. impact: | New accounts must change their password every {{ max_days }} days and are disabled {{ inactive_days }} days after it expires. Existing accounts are handled by CB-DEB-AUTH-015. notes: | NIST SP 800-63B advises against forced periodic changes when passwords are long and checked against breach lists. Set `max_days` to 99999 in your tailoring file if you follow that model and rely on the quality and lockout controls instead. setting: location: /etc/login.defs, /etc/default/useradd default_value: "PASS_MAX_DAYS 99999, PASS_MIN_DAYS 0, PASS_WARN_AGE 7, INACTIVE -1" recommended_value: "PASS_MAX_DAYS <= {{ max_days }}, PASS_MIN_DAYS >= {{ min_days }}, PASS_WARN_AGE >= 7, YESCRYPT or SHA512, INACTIVE <= {{ inactive_days }}" parameters: - name: max_days type: integer description: Maximum password age in days. unit: days default: 365 minimum: 1 maximum: 99999 - name: min_days type: integer description: Minimum days between password changes. unit: days default: 0 profile_defaults: server-hardened: 1 desktop-hardened: 1 minimum: 0 maximum: 7 - name: inactive_days type: integer description: Days after password expiry before the account is disabled. unit: days default: 45 minimum: 0 maximum: 365 audit: manual: | 1. In `/etc/login.defs`: `PASS_MAX_DAYS` <= {{ max_days }}, `PASS_MIN_DAYS` >= {{ min_days }}, `PASS_WARN_AGE` >= 7, `ENCRYPT_METHOD` is `YESCRYPT` or `SHA512`. 2. `useradd -D | grep INACTIVE` shows a value between 0 and {{ inactive_days }}. checks: - id: login-defs engine: shell description: Aging and hashing settings in /etc/login.defs. spec: script: | get() { sed -n "s/^[[:space:]]*$1[[:space:]]\{1,\}\([^[:space:]]*\).*/\1/p" /etc/login.defs | tail -n 1; } max=$(get PASS_MAX_DAYS) min=$(get PASS_MIN_DAYS) warn=$(get PASS_WARN_AGE) enc=$(get ENCRYPT_METHOD) echo "PASS_MAX_DAYS=$max PASS_MIN_DAYS=$min PASS_WARN_AGE=$warn ENCRYPT_METHOD=$enc" [ "${max:-99999}" -le "$CB_MAX_DAYS" ] && [ "${min:-0}" -ge "$CB_MIN_DAYS" ] && [ "${warn:-0}" -ge 7 ] \ && { [ "$enc" = YESCRYPT ] || [ "$enc" = SHA512 ]; } - id: inactive engine: shell description: Default INACTIVE of useradd. spec: script: | i=$(useradd -D | sed -n 's/^INACTIVE=//p') echo "INACTIVE=$i" [ "${i:--1}" -ge 0 ] && [ "${i:--1}" -le "$CB_INACTIVE_DAYS" ] remediation: manual: | 1. Set in `/etc/login.defs`: `PASS_MAX_DAYS {{ max_days }}`, `PASS_MIN_DAYS {{ min_days }}`, `PASS_WARN_AGE 7` and keep `ENCRYPT_METHOD` at `YESCRYPT` (or `SHA512`). 2. Run `useradd -D -f {{ inactive_days }}`. effects: restart: none disruption: none lockout_risk: false rollback: | Restore `/etc/login.defs` and `/etc/default/useradd` from the backup. scripts: - id: defaults engine: shell content: | f=/etc/login.defs cb_backup "$f" cb_backup /etc/default/useradd set_def() { if grep -Eq "^[[:space:]]*$1[[:space:]]" "$f"; then sed -i "s/^[[:space:]]*$1[[:space:]].*/$1\t$2/" "$f"; else printf '%s\t%s\n' "$1" "$2" >>"$f"; fi } set_def PASS_MAX_DAYS "$CB_MAX_DAYS" set_def PASS_MIN_DAYS "$CB_MIN_DAYS" w=$(sed -n 's/^[[:space:]]*PASS_WARN_AGE[[:space:]]\{1,\}\([0-9]*\).*/\1/p' "$f" | tail -n 1) [ "${w:-0}" -ge 7 ] || set_def PASS_WARN_AGE 7 e=$(sed -n 's/^[[:space:]]*ENCRYPT_METHOD[[:space:]]\{1,\}\([A-Z0-9]*\).*/\1/p' "$f" | tail -n 1) case $e in YESCRYPT | SHA512) ;; *) set_def ENCRYPT_METHOD YESCRYPT ;; esac useradd -D -f "$CB_INACTIVE_DAYS" references: - title: login.defs(5), Debian manual pages url: https://manpages.debian.org/trixie/login.defs/login.defs.5.en.html publisher: Debian kind: vendor-doc accessed: 2026-10-18 - title: useradd(8), Debian manual pages url: https://manpages.debian.org/trixie/passwd/useradd.8.en.html publisher: Debian kind: vendor-doc accessed: 2026-10-18 - title: NIST SP 800-63B - Digital Identity Guidelines, Authentication url: https://pages.nist.gov/800-63-4/sp800-63b.html publisher: NIST kind: standard accessed: 2026-10-18 mappings: - framework: nist-800-53r5 framework_version: "5.1.1" id: IA-5(1) relation: partial - framework: nist-800-53r5 framework_version: "5.1.1" id: AC-2(3) relation: partial - framework: cis-debian-12 framework_version: "2.0.0" id: "5.4.1.1" relation: partial - framework: cis-debian-12 framework_version: "2.0.0" id: "5.4.1.2" relation: partial - framework: cis-debian-12 framework_version: "2.0.0" id: "5.4.1.3" relation: partial - framework: cis-debian-12 framework_version: "2.0.0" id: "5.4.1.4" relation: equivalent - framework: cis-debian-12 framework_version: "2.0.0" id: "5.4.1.5" relation: partial - framework: cis-debian-13 framework_version: "1.1.0" id: "5.4.1.1" relation: partial - framework: cis-debian-13 framework_version: "1.1.0" id: "5.4.1.2" relation: partial - framework: cis-debian-13 framework_version: "1.1.0" id: "5.4.1.3" relation: partial - framework: cis-debian-13 framework_version: "1.1.0" id: "5.4.1.4" relation: equivalent - framework: cis-debian-13 framework_version: "1.1.0" id: "5.4.1.5" relation: partial threats: - framework: mitre-attack id: T1078.003 related_controls: - id: CB-DEB-AUTH-015 type: related authors: - name: Alice github: Sn0wAlice verified: - date: 2026-10-18 by: Sn0wAlice versions: ["12"] environment: Proxmox VM, Debian 12 genericcloud image, kernel 6.1.0-54-cloud-amd64 notes: Generated check, fix and check again for profiles core and server-hardened; state kept after reboot. - date: 2026-10-18 by: Sn0wAlice versions: ["13"] environment: Proxmox VM, Debian 13 genericcloud image, kernel 6.12.113+deb13-cloud-amd64 notes: Generated check, fix and check again for profiles core and server-hardened; state kept after reboot. introduced_in: 0.1.0 created: 2026-10-18 updated: 2026-10-18