← All rules
SOCLE-CLD-IAM-007// Accountsmediuminventory state

Ensure all users last password change date is in the past

No account may carry a last password change date set in the future. A future date in the third field of /etc/shadow makes the system believe the password was just changed, which neutralises PASS_MAX_DAYS expiry for that account.

Checked against what is installed or registered, packages present/absent, account databases.

A pass proves✓ running now✓ on disk✓ survives rebootthe qualified verdict →
Debian 12CIS 1.1.0Debian 13CIS 1.0.0FedoraRHEL 10 / Rocky 10 / AlmaLinux 10RHEL 8 / Rocky 8 / AlmaLinux 8CIS 4.0.0RHEL 9 / Rocky 9 / AlmaLinux 9CIS 2.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04
One check, maps to 2 standards

A mapping is a cross-reference to where each standard places this requirement, anchored and cross-validated, not a claim of equivalence. A passing check is evidence toward these references, how to read it.

Why this rule matters

If a user recorded password change date is in the future then they could bypass any set password expiration.

What Pavois checks

Pavois computes today's epoch-day count (d=$(( $(date +%s) / 86400 ))) and compares it against the third field (lastchg) of every line of /etc/shadow with awk. Any account whose lastchg is strictly greater than today makes the control fail. This audits the shadow database as the system actually reads it, account by account, not a policy file: a single tampered or clock-skewed entry is enough to fail.

describe command('d=$(( $(date +%s) / 86400 )); awk -v d="$d" \'BEGIN{FS=":"}($3 ~ /^[0-9]+$/ && $3+0>d){c++} END{print c?"ko":"ok"}\' /etc/shadow') do
  its('stdout.strip') { should eq 'ok' }
end

How to verify it is applied

List the offending accounts directly:

awk -F: -v d=$(( $(date +%s) / 86400 )) '($3 ~ /^[0-9]+$/ && $3+0 > d){print $1, $3}' /etc/shadow

Expected output: nothing. For a single user, chage -l <user> must show a Last password change date that is today or earlier.

Inspect & investigate

A future lastchg value generates no log of its own: it is a silent state in /etc/shadow. The write that produced it is visible if the identity file watch is active, in the audit log:

grep 'key="usergroup_modification"' /var/log/audit/audit.log

(Grep the raw log rather than trusting ausearch, which reports false "no matches".) A legitimate change through chage or passwd also leaves a line in /var/log/auth.log, for example chage[2345]: changed password expiry for alice.

Remediation

Pavois classifies this as a manual remediation: a future date is a per-account anomaly and rewriting it blindly could reset a legitimate expiry window. The delivered script only lists the affected accounts with the same awk test, then leaves you to apply, after review, chage -d $(date +%F) <user> on each one, which stamps the last change date to today.

Pavois applies this with its own harden engine, the plan below, not a shell script:

commandd=$(( $(date +%s) / 86400 )); awk -F: -v d="$d" '($3 ~ /^[0-9]+$/ && $3+0>d){print $1}' /etc/shadow # for each listed user: chage -d $(date +%F) <user> (set last change to today)
reasona future last-change date is per-user, fix each with chage after review
resourcemanual
pavois harden plan local

where the target is local, a user@host SSH alias, or a container , Docs

Impact & precautions

An account with a future lastchg never expires: a stolen password stays valid past every rotation window, and the anomaly is often the fingerprint of a tampered shadow file or of a host whose clock jumped. Before running chage -d, investigate the cause (check timedatectl: a wrong system clock will simply recreate the finding). Be careful with the opposite mistake: setting lastchg to 0 forces a password change at next login, and doing that on a service or automation account locks it out immediately because it cannot answer the interactive prompt. Use today's date, not 0, and keep a root session open while you fix administrative accounts.

Standards mapping

StandardReferenceTypeVersionConfidence
CIS5.4.1.6directper OS, see the benchmark tablehigh
PCI DSS8.3.5supporting4.0.1medium

Each reference is a cross-reference anchored in the upstream benchmark and cross-validated against the SCAP Security Guide and ansible-lockdown, not a claim of equivalence. Direct = a prescriptive, line-level requirement; supporting = an abstract control family (NIST) the check provides evidence toward. How to read a mapping.

Sources & references