[REQ-END-163] Account Policy: Password Policy for Endpoints
Target Scope
- Applicable Systems: Tier 2 Client Workstations and Member Servers.
- Operating Systems: Windows 10 Enterprise/Professional (1809 and above), Windows 11 Enterprise/Professional (all builds), Windows Server 2016 (and above).
Implementation Details
- Priority: High
- Policy Category: Computer Configuration -> Windows Settings -> Security Settings -> Account Policies -> Password Policy / Local Policies -> Security Options
- Policy Settings:
- Enforce password history:
24passwords remembered - Maximum password age:
0days (never expire) - Minimum password age:
1day - Minimum password length:
14characters - Password must meet complexity requirements:
Enabled - Store passwords using reversible encryption:
Disabled - Relax minimum password length limits:
Enabled - Interactive logon: Prompt user to change password before expiration:
14days
- Enforce password history:
- Supported On: Windows 10 / Windows 11 / Windows Server 2016 and above
- SecEdit / Registry Parameters:
MinimumPasswordLength=14(Characters required; relaxed boundary enabled)PasswordComplexity=1(Requires uppercase, lowercase, numbers, and symbols)PasswordHistorySize=24(Distinct past passwords retained)MaxPasswordAge=0(Zero days = expiration disabled per NIST SP 800-63B)MinPasswordAge=1(Days before a user can change their password again)ClearTextPassword=0(Reversible encryption prohibited)RelaxMinPasswordLengthLimits=1(Allows password lengths exceeding 14 characters, up to 128)HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\PasswordExpiryWarning=14(REG_DWORD)
- Vulnerability References:
Rationale
Establishing a hardened password baseline across enterprise client workstations and member servers protects against password guessing, automated spray campaigns, and offline cryptanalysis:
Technical Threat Vectors and Defense Mechanics
- Elevating Entropy via Length (
MinimumPasswordLength = 14): In modern credential security, password length is the single most decisive factor determining resistance to offline cracking. Short 8-character passwords, even when complex, represent a keyspace of roughly6.6 x 10^15combinations, which high-end GPU rigs can exhaust rapidly. Elevating the minimum length to 14 characters expands the search space to over4.6 x 10^27combinations. Offline dictionary and brute-force cracking tools are rendered computationally infeasible against hashes of this length. - Modern Expiration Guidance (
MaxPasswordAge = 0): In compliance with NIST SP 800-63B, Microsoft Security Baselines, and ANSSI recommendations, periodic password resets (such as 60-day or 90-day cycles) are counterproductive. Frequent forced expirations prompt users to pick easily predictable modifications (e.g., changingSpring2025!toSummer2025!) or write passwords down. Coupling a strong 14-character minimum length with no expiration (MaxPasswordAge = 0) improves overall security by eliminating predictable patterns. Rapid credential rotation protocols remain reserved for events where account compromise is suspected. - Disabling Reversible Encryption (
ClearTextPassword = 0): Storing passwords using reversible encryption encrypts passwords using an algorithm whose key is known to the operating system. If an adversary gains access to the SAM database, they can reverse the encryption and retrieve plaintext passwords. Disabling reversible encryption ensures that only irreversible one-way cryptographic hashes are stored. - Preventing Rapid Password Cycling (
PasswordHistorySize = 24,MinPasswordAge = 1): Retaining a history of 24 passwords ensures users cannot reuse recent credentials. Pairing this with a 1-day minimum password age prevents users from immediately resetting their password 24 times consecutively to return to their original password. - Enabling Relaxed Password Length Limits (
RelaxMinPasswordLengthLimits = 1): Windows historically capped the GUI configuration of minimum password length at 14 characters. EnablingRelaxMinPasswordLengthLimitsallows modern Windows systems to accept passphrases up to 128 characters without truncation or buffer issues. - Endpoint vs PAW Comparison: Standard Tier 2 endpoints enforce a 14-character minimum length to balance robust entropy with day-to-day business user experience. On Tier 0 PAWs, this threshold is tightened to 20 characters to provide extreme resistance for directory administrative accounts.
Legacy Impact & Compatibility
- End-User Password Updates: When users next update their passwords, they will be required to provide a passphrase of at least 14 characters meeting complexity requirements. Organizations should train users on passphrase construction (e.g., combining 4 or 5 random words).
- Legacy Service Accounts: Hardcoded service accounts or third-party legacy applications with short password limitations must be identified and upgraded to support 14+ character passphrases or migrated to Group Managed Service Accounts (gMSAs).
- LAPS for Local Administrators: Local administrator accounts on member servers and workstations should be managed via Windows LAPS, configured to generate 14+ character randomized passwords automatically.
Implementation Steps
Option A: Group Policy Object (GPO) Configuration (Preferred)
- Open the Group Policy Management Console (
gpmc.msc). - Edit the Default Domain Policy or target GPO linked to workstations and member servers (e.g.,
GPO_Hardening_Endpoints). - Navigate to:
Computer Configuration\Policies\Windows Settings\Security Settings\Account Policies\Password Policy - Configure the following settings:
- Enforce password history: Set to
24passwords remembered - Maximum password age: Set to
0days (never expire) - Minimum password age: Set to
1day - Minimum password length: Set to
14characters - Password must meet complexity requirements: Set to
Enabled - Store passwords using reversible encryption: Set to
Disabled - Relax minimum password length limits: Set to
Enabled
- Enforce password history: Set to
- Navigate to:
Computer Configuration\Policies\Windows Settings\Security Settings\Local Policies\Security Options - Configure:
- Interactive logon: Prompt user to change password before expiration: Set to
14days
- Interactive logon: Prompt user to change password before expiration: Set to
- Link the GPO to the target Organizational Units and force replication.
Option B: PowerShell & Registry Configuration (Remediation / Non-GPO)
Download Script: Configure-EndAccountPasswordPolicy.ps1
# Configure-EndAccountPasswordPolicy.ps1
# Description: Configures Endpoint password policy (14 char minimum, relaxed limits, no expiration) via SecEdit.
Write-Host "Configuring Endpoint password policy..." -ForegroundColor Cyan
# 1. Configure PasswordExpiryWarning via Registry
$WinlogonPath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
if (-not (Test-Path $WinlogonPath)) {
New-Item -Path $WinlogonPath -Force | Out-Null
}
Set-ItemProperty -Path $WinlogonPath -Name "PasswordExpiryWarning" -Value 14 -Type DWord -Force
# 2. Configure SecEdit System Access password parameters
$SecTempDir = Join-Path $env:TEMP "EndpointPasswordSecTemplate"
if (-not (Test-Path $SecTempDir)) {
New-Item -Path $SecTempDir -ItemType Directory -Force | Out-Null
}
$CfgFile = Join-Path $SecTempDir "end_password.cfg"
$DbFile = Join-Path $SecTempDir "end_password.sdb"
$LogFile = Join-Path $SecTempDir "end_password.log"
$Process = Start-Process secedit -ArgumentList "/export /cfg `"$CfgFile`"" -Wait -NoNewWindow -PassThru
if ($Process.ExitCode -ne 0) {
Throw "Failed to export current security template."
}
$ConfigText = Get-Content -Path $CfgFile -Raw
if ($ConfigText -notmatch "\[System Access\]") {
$ConfigText += "`r`n[System Access]`r`n"
}
$Lines = $ConfigText -split "`r?`n"
$NewLines = @()
$InSystemAccess = $false
$PwdSettings = @{
"MinimumPasswordLength" = 14
"PasswordComplexity" = 1
"PasswordHistorySize" = 24
"MaxPasswordAge" = 0
"MinPasswordAge" = 1
"ClearTextPassword" = 0
"RelaxMinPasswordLengthLimits" = 1
}
foreach ($Line in $Lines) {
if ($Line -match "^\[(.*)\]$") {
if ($Matches[1] -eq "System Access") {
$InSystemAccess = $true
} else {
$InSystemAccess = $false
}
}
if ($InSystemAccess) {
$IsManaged = $false
foreach ($Key in $PwdSettings.Keys) {
if ($Line -match "^\s*$($Key)\s*=") {
$IsManaged = $true
break
}
}
if (-not $IsManaged) {
$NewLines += $Line
}
} else {
$NewLines += $Line
}
}
$FinalLines = @()
foreach ($Line in $NewLines) {
$FinalLines += $Line
if ($Line -eq "[System Access]") {
foreach ($Key in $PwdSettings.Keys) {
$Val = $PwdSettings[$Key]
$FinalLines += "$($Key) = $($Val)"
}
}
}
$FinalLines -join "`r`n" | Out-File -FilePath $CfgFile -Encoding ascii -Force
$Proc = Start-Process secedit -ArgumentList "/configure /db `"$DbFile`" /cfg `"$CfgFile`" /areas SECURITYPOLICY /log `"$LogFile`"" -Wait -NoNewWindow -PassThru
if ($Proc.ExitCode -ne 0) {
Throw "Failed to apply SecEdit password policy."
}
Remove-Item -Path $SecTempDir -Recurse -Force -ErrorAction SilentlyContinue
Write-Host "Endpoint password policy applied successfully." -ForegroundColor Green
To audit the hardening status:
Download Script: Get-EndAccountPasswordPolicyStatus.ps1
# Get-EndAccountPasswordPolicyStatus.ps1
# Description: Audits Endpoint password policy parameters via SecEdit and registry queries.
Write-Host "--- Auditing Endpoint Password Policy ---" -ForegroundColor Cyan
$script:Vulnerable = $false
# 1. Audit Registry Setting
$WinlogonPath = "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon"
if (-not (Test-Path $WinlogonPath)) {
Write-Host " [!] MISSING KEY: $WinlogonPath" -ForegroundColor Red
$script:Vulnerable = $true
} else {
$WarnVal = (Get-ItemProperty -Path $WinlogonPath -Name "PasswordExpiryWarning" -ErrorAction SilentlyContinue).PasswordExpiryWarning
if ($null -eq $WarnVal -or $WarnVal -lt 5 -or $WarnVal -gt 14) {
Write-Host " [!] VULNERABLE: PasswordExpiryWarning is set to '$WarnVal' (Expected: 5-14)" -ForegroundColor Red
$script:Vulnerable = $true
} else {
Write-Host " [+] PasswordExpiryWarning: $WarnVal (Secure)" -ForegroundColor Green
}
}
# 2. Audit SecEdit Settings
$SecTempDir = Join-Path $env:TEMP "EndpointPasswordAuditTemplate"
if (-not (Test-Path $SecTempDir)) {
New-Item -Path $SecTempDir -ItemType Directory -Force | Out-Null
}
$CfgFile = Join-Path $SecTempDir "end_password_audit.cfg"
$Process = Start-Process secedit -ArgumentList "/export /cfg `"$CfgFile`"" -Wait -NoNewWindow -PassThru
if ($Process.ExitCode -ne 0) {
Write-Output "Non-Compliant"
exit 1
}
$ConfigContent = Get-Content -Path $CfgFile -Raw
Remove-Item -Path $SecTempDir -Recurse -Force -ErrorAction SilentlyContinue
$ExpectedSettings = @{
"MinimumPasswordLength" = 14
"PasswordComplexity" = 1
"PasswordHistorySize" = 24
"MaxPasswordAge" = 0
"MinPasswordAge" = 1
"ClearTextPassword" = 0
"RelaxMinPasswordLengthLimits" = 1
}
foreach ($Key in $ExpectedSettings.Keys) {
$Expected = $ExpectedSettings[$Key]
if ($ConfigContent -match "(?m)^\s*$($Key)\s*=\s*(.*)\s*$") {
$Actual = $Matches[1].Trim()
} else {
$Actual = ""
}
if ($Actual -ne [string]$Expected) {
Write-Host " [!] VULNERABLE: $($Key) = '$Actual' (Expected: '$Expected')" -ForegroundColor Red
$script:Vulnerable = $true
} else {
Write-Host " [+] $($Key): $Actual (Secure)" -ForegroundColor Green
}
}
if ($script:Vulnerable) {
Write-Output "Non-Compliant"
exit 1
} else {
Write-Output "Compliant"
exit 0
}
Option C: Manual Verification
Verify the active local password policy settings using net accounts:
net accounts
Confirm that Minimum password length indicates 14, Length of password history maintained is 24, and Maximum password age (days) indicates Unlimited (value 0).
Verify the password expiration warning registry value:
reg query "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon" /v PasswordExpiryWarning
Confirm that PasswordExpiryWarning is set to 0xe (Decimal 14).
Sources & Compliance References
- CIS Microsoft Windows 10 Enterprise Benchmark: Section 1.1.1 (Enforce password history >= 24), Section 1.1.2 (Maximum password age), Section 1.1.3 (Minimum password age >= 1), Section 1.1.4 (Minimum password length >= 14), Section 1.1.5 (Password complexity = Enabled), Section 1.1.6 (Relax minimum password length limits = Enabled), Section 1.1.7 (Reversible encryption = Disabled), Section 2.3.7.8 (PasswordExpiryWarning)
- CIS Microsoft Windows 11 Enterprise Benchmark: Section 1.1.1 through 1.1.7, Section 2.3.7.8
- CIS Microsoft Windows Server 2022 Benchmark: Section 1.1.1 through 1.1.7, Section 2.3.7.8
- DoD Windows 11 Computer STIG: Rule SV-220703r879603_rule (Minimum password length), Rule SV-220704r879604_rule (Password complexity), Rule SV-220706r879606_rule (Password history)
- NIST SP 800-63B: Digital Identity Guidelines - Authentication and Lifecycle Management (Section 5.1.1.2 Memorized Secret Authenticators)
- ANSSI Active Directory Hardening Guide: Recommendations on password length, entropy, and disabling reversible encryption
- Microsoft Security Baseline Focus: Windows Client Security Baseline - Password Policies
- Related Controls: REQ-PAW-152: Account Policy: Password Policy for PAWs, REQ-END-164: Account Policy: Account Lockout Policy for Endpoints