What Are Stale and Over-Privileged Accounts?
Active Directory environments accumulate accounts over time. Employees leave, contractors finish engagements, service accounts are created for projects that end โ and the accounts remain. These stale accounts are forgotten by IT but fully functional: valid credentials, valid group memberships, valid access to resources.
Alongside stale accounts, over-privileged accounts are a parallel risk: users, IT staff, and service accounts that accumulated permissions far beyond what their role requires. Both represent the same threat โ a credential an attacker can target that provides more access than it should.
Stale and over-privileged accounts are among the most reliable initial access and lateral movement vectors in real-world intrusions. They are quiet, they persist for years, and they require no exploitation โ just enumeration and a credential.
How It Works
AD accounts remain active until explicitly disabled or deleted. When an employee leaves, IT must manually disable their account, remove group memberships, and eventually delete the object. When this process is skipped โ or when contractors, service accounts, and shared accounts are not tracked โ the result is an AD environment full of accounts that:
- Have not authenticated in months or years
- Still belong to privileged groups
- Have passwords that were set years ago and never changed
- Are not subject to any password policy (no Fine-Grained Password Policy configured)
From an attacker's perspective, a stale Domain Admin account from a former IT employee is the ideal target: high privilege, low monitoring, password unchanged for years.
The Attack Chain
Step 1 - Enumerate Stale and High-Value Accounts
# Find enabled accounts with no login in 90+ days
$cutoff = (Get-Date).AddDays(-90)
Get-ADUser -Filter {Enabled -eq $true -and LastLogonDate -lt $cutoff} `
-Properties LastLogonDate, PasswordLastSet, MemberOf |
Select-Object SamAccountName, LastLogonDate, PasswordLastSet |
Sort-Object LastLogonDate
# Find all members of privileged groups
$groups = @("Domain Admins","Enterprise Admins","Schema Admins","Backup Operators","Account Operators")
foreach ($group in $groups) {
Get-ADGroupMember -Identity $group -Recursive |
Get-ADUser -Properties LastLogonDate, PasswordLastSet |
Select-Object @{N="Group";E={$group}}, SamAccountName, LastLogonDate, PasswordLastSet
}
Step 2 - Target Accounts With Old Passwords
Accounts with passwords set years ago are prime spray and brute-force targets โ they were created before modern password policies and may use predictable patterns like Company2018! or Welcome1:
# Spray known weak patterns against stale accounts
kerbrute passwordspray --dc 10.10.0.1 --domain corp.local stale_users.txt "Winter2020!"
Step 3 - Exploit Excessive Privileges
A compromised stale account that is still a member of Domain Admins provides immediate full domain access โ despite the user having left the organization years ago:
# Attacker using stolen stale DA account
# Full domain access โ DCSync, GPO modification, lateral movement
lsadump::dcsync /domain:corp.local /all
Step 4 - Persistence Through Overlooked Accounts
Stale accounts are rarely monitored. An attacker using a long-forgotten service account generates no alerts because the account has had no activity for years โ any sign-in baseline is stale or nonexistent.
Detection
Windows Event IDs
| Event ID | Source | What to Look For |
|---|---|---|
| 4624 | DC/Workstation | Successful logon from an account with no recent activity |
| 4768 | DC - Security | TGT requested for an account inactive for 90+ days |
| 4728/4732 | DC - Security | Member added to privileged group โ unexpected additions |
| 4720 | DC - Security | New account created โ track all new AD account creation |
Behavioral Anomalies
- First logon in 6+ months from any account, especially privileged ones
- Privileged group membership for accounts with old
PasswordLastSetdates - Service accounts authenticating interactively (they should only do so as services)
- Shared accounts (multiple users logging in from different IPs in short windows)
SIEM Detection Query (Elastic KQL)
event.code: "4624" AND
winlog.event_data.LogonType: "3" AND
winlog.event_data.TargetUserName: (* AND NOT "*$")
| where @timestamp - lastActivity > 90d
Remediation
๐ก Quick Win: Pull a list of all enabled accounts with
LastLogonDateolder than 90 days and disable them immediately. This is a no-risk action โ disabled accounts can be re-enabled in seconds if needed.
1. Disable Stale Accounts
# Disable all accounts inactive for 90+ days (excludes service accounts by OU)
$cutoff = (Get-Date).AddDays(-90)
Get-ADUser -Filter {Enabled -eq $true -and LastLogonDate -lt $cutoff} `
-SearchBase "OU=Users,DC=corp,DC=local" `
-Properties LastLogonDate | ForEach-Object {
Disable-ADAccount -Identity $_
Write-Host "Disabled: $($_.SamAccountName) โ Last login: $($_.LastLogonDate)"
}
2. Audit and Reduce Privileged Group Membership
# Export all privileged group members for review
$groups = @("Domain Admins","Enterprise Admins","Schema Admins")
$groups | ForEach-Object {
Get-ADGroupMember -Identity $_ -Recursive |
Select-Object @{N="Group";E={$_}}, SamAccountName, distinguishedName
} | Export-Csv privileged_members.csv -NoTypeInformation
Apply the principle of least privilege: Domain Admins should be used only when required, and membership should be minimal (2-5 accounts maximum for a typical environment).
3. Configure Fine-Grained Password Policies for Privileged Accounts
# Create a strict PSO for privileged accounts
New-ADFineGrainedPasswordPolicy -Name "PrivilegedAccountsPSO" `
-Precedence 10 `
-MinPasswordLength 20 `
-ComplexityEnabled $true `
-PasswordHistoryCount 24 `
-MaxPasswordAge (New-TimeSpan -Days 60) `
-LockoutThreshold 3
# Apply to Domain Admins group
Add-ADFineGrainedPasswordPolicySubject -Identity "PrivilegedAccountsPSO" `
-Subjects "Domain Admins"
4. Implement Account Lifecycle Governance
- Offboarding checklist: disable AD account on last day, remove privileged group memberships, document service accounts owned by the employee
- Quarterly access review: review all privileged group memberships for continued business justification
- Service account inventory: maintain a register of all service accounts, their purpose, owner, and associated systems
How EtcSec Detects This
EtcSec performs a complete account lifecycle audit on every scan.
EXCESSIVE_PRIVILEGED_ACCOUNTS flags environments with more privileged accounts than typical for the organization size โ a clear indicator of privilege creep over time.
PASSWORD_VERY_OLD identifies accounts where the password has not been changed in over a year, prioritized by account privilege level โ stale DA passwords appear at the top.
FGPP_NOT_CONFIGURED detects environments with no Fine-Grained Password Policies, meaning privileged accounts are subject to the same (often weak) domain-wide policy as regular users.
โน๏ธ Note: EtcSec audits account lifecycle and privilege posture automatically on every scan. Run a free audit to discover stale and over-privileged accounts in your environment.
Related articles: Active Directory Password Security | ACL Abuse and DCSync


