Every directory and application accumulates accounts that no longer belong to anyone or that nobody uses, and each one is a working credential that attracts no attention when an attacker signs in with it. Joiner, mover and leaver processes are meant to prevent this, but they fail quietly: an HR record is corrected, a contractor is never entered in HR at all, an application keeps its own local users, or a test account outlives its project. This guide is about detection and clean-up rather than process: how to define orphaned and dormant accounts precisely, how to find them by correlating accounts with authoritative sources, which last-activity attributes can and cannot be trusted, what inactivity thresholds to set, and how to disable, then delete, without breaking services. It is written for identity governance, IAM and audit practitioners. The process side is covered in the Joiner-Mover-Leaver Guide.
Key takeaways
- Orphaned and dormant are different problems. An orphaned account has no valid owner; a dormant account has an owner but no recent use. They are found with different data and fixed with different actions.
- Correlation is the core control. An account that cannot be matched to a current HR record, contractor record or named owner is orphaned until proven otherwise, whatever its activity.
- Last-activity data is less reliable than it looks. Active Directory's replicated lastLogonTimestamp can lag by up to about two weeks, and Entra ID's lastSignInDateTime records failed attempts too. Know what each attribute measures before acting on it.
- Disable first, delete later. A disable-and-wait stage with a fixed hold period catches the service that turns out to depend on an "unused" account, and keeps audit history intact.
- Exceptions must be named and dated. Break-glass accounts, seasonal staff and people on long leave are legitimate reasons to keep a dormant account, but only with an owner, a reason and an expiry recorded.
Definitions that hold up in an audit
| Term | Definition | Typical cause | Primary data source |
|---|---|---|---|
| Orphaned account | An enabled account with no current, valid person or accountable owner behind it | Leaver not processed in one system, contractor end date missed, owner of a shared account left | HR, contractor and owner records |
| Uncorrelated account | An account an IGA platform or reconciliation job cannot match to any identity by its correlation rule | Local application users, naming mismatches, accounts created outside provisioning | IGA aggregation results |
| Dormant (inactive) account | An enabled account with no successful authentication within a defined period | Role change, project ended, access never needed | Directory and application sign-in data |
| Stale account | Commonly used for either of the above; define it in policy or avoid the term | Mixed | Both |
| Orphaned non-human identity | A service account, application identity, API key or token whose creator, owner or consuming system no longer exists | Owner left, application retired, integration abandoned | Ownership records, credential last-used data |
NIST SP 800-53 Rev. 5 control AC-2(3) captures both conditions in one requirement: disable accounts within an organisation-defined time when they have expired, are no longer associated with a user or individual, are in violation of policy, or have been inactive for an organisation-defined period. The second clause is the orphaned case; the fourth is the dormant case. Write both periods into your account management standard so an auditor can test against them.
Finding orphaned accounts by correlation
Correlation means matching every account in every system to an identity in an authoritative source. An account that does not match is the finding, not the exception.
- Choose the authoritative sources: HR for employees; a contractor or vendor management system for non-employees; a CMDB or ownership register for service accounts and application identities. If contractors are not held anywhere authoritative, that gap is the largest single source of orphans and should be fixed first.
- Pick a stable correlation key: an immutable employee or worker ID written to the account at provisioning (for example the employeeID attribute in Active Directory, or an extension attribute synchronised to the cloud directory). Correlating on display name or email address breaks on name changes and rehires.
- Aggregate every account source: directories, cloud identity providers, SaaS applications, databases, operating system local accounts, network devices and privileged access vaults. Local application accounts outside single sign-on are where orphans hide longest.
- Classify the unmatched set: matched to a terminated identity (orphaned, high priority); matched to nobody (uncorrelated, investigate); non-human with no owner (orphaned NHI); matched but owner inactive (route to manager).
- Assign an owner or remove: every uncorrelated account gets either a named owner and a correlation entry within a set period, or it enters the disable workflow.
- Repeat continuously: run correlation on every aggregation, not once a year. An IGA platform does this natively; without one, a scheduled export and join against an HR extract achieves the same result for core systems.
- Terminated but enabled: the highest-risk class. Report it daily and treat any successful sign-in by such an account as a security incident.
- Rehires and transfers: correlate on the worker ID, not on the account. A rehired employee should not silently inherit a previous account that kept old entitlements.
- Shared and generic accounts: an account such as "reception" or "scanner" cannot be correlated to a person, so it must have a named accountable owner instead. See the Shared and Generic Accounts Governance Guide.
Finding dormant accounts: which activity data to trust
| Platform | Attribute or report | What it actually records | Caveat |
|---|---|---|---|
| Active Directory | lastLogonTimestamp | Replicated domain-wide; updated at logon only when the stored value is older than the msDS-LogonTimeSyncInterval | Default interval is 14 days with randomisation, so the value can lag real use by up to about two weeks. Use it for stale detection, not exact times |
| Active Directory | lastLogon | Exact last logon processed by one domain controller | Not replicated: query every domain controller and take the latest |
| Active Directory | Search-ADAccount -AccountInactive -TimeSpan | Accounts that have not logged on within the period | Combine with -UsersOnly to separate computer accounts; also report -PasswordNeverExpires |
| Microsoft Entra ID | signInActivity.lastSignInDateTime | Last interactive sign-in attempt, successful or not | Failed attacks against a dead account make it look active |
| Microsoft Entra ID | signInActivity.lastNonInteractiveSignInDateTime | Last non-interactive attempt by a client for the user | Refresh tokens can keep this current long after the person stopped working |
| Microsoft Entra ID | signInActivity.lastSuccessfulSignInDateTime | Most recent successful interactive or non-interactive sign-in | Best single field; available from 1 December 2023 and not backfilled, so null may mean "before December 2023" |
| AWS IAM | Credential report: password_last_used, access_key_N_last_used_date | Last console password use and last API use per access key | Report covers the first two keys only; generate at most every four hours |
| AWS IAM | Last accessed information | Last attempted use of each allowed service, tracked for at least 400 days | Includes denied attempts; confirm in CloudTrail before acting |
- Use success, not attempts: wherever a platform separates successful from attempted sign-ins, base dormancy on successful use. An account under password-spray attack should not be protected from clean-up by the attack itself.
- Treat null as unknown: an empty last-activity value can mean "never used" or "used before tracking began". In Entra ID, interactive sign-in data goes back to April 2020; in AWS, password tracking began on 20 October 2014. Never-used accounts older than 30 days are themselves a finding.
- Check application-level activity: a user can be active in the directory and dormant in a sensitive application. For entitlement clean-up, application last-use matters more than tenant sign-in.
- Licensing and permissions: in Entra ID, reading lastSuccessfulSignInDateTime through Microsoft Graph requires Entra ID P1 or P2 and the AuditLog.Read.All and User.Read.All permissions. The reporting identity itself is privileged; scope and monitor it.
Setting inactivity thresholds
| Account class | Suggested threshold | Rationale |
|---|---|---|
| Privileged and administrator accounts | 30 days or less | Highest impact; admins who need access sign in often |
| Standard workforce accounts | 45 to 90 days | CIS Controls v8.1 Safeguard 5.3 sets 45 days; Microsoft notes many organisations use 90 to 180 days |
| Guest and external accounts | 30 to 90 days | No HR record to trigger removal, so inactivity is often the only signal |
| Remote access (VPN, VDI) profiles | 30 days | Internet-facing and a known ransomware entry route |
| Service accounts and API keys | Based on expected schedule (for example, a quarterly job allows about 100 days) | Non-human use is periodic; derive the threshold from the documented run frequency |
| Never-used accounts | 30 days after creation | Provisioned but never collected access is pure exposure |
Pick thresholds you can enforce automatically. A 45-day rule that is reviewed manually once a year delivers less than a 90-day rule enforced every night. Microsoft Entra access reviews mark users who have not signed in for 30 days with a recommended action of Deny, which is a useful reviewer prompt even where the policy threshold is longer.
Disable, hold, then delete
- Notify: for dormant accounts with a known owner, notify the user and manager with a deadline (for example seven days) to confirm need. Orphaned accounts skip this step.
- Disable: disable the account, revoke sessions and refresh tokens, and remove it from privileged groups. In cloud directories, disabling alone may not end existing sessions; trigger session revocation explicitly.
- Tag and move: record the reason, date and ticket in an attribute and move the account to a quarantine organisational unit or group excluded from access policies.
- Hold: keep it disabled for a fixed period (30 to 90 days is common). Monitor for failed authentication against it: a failing scheduled task or an attacker probing are both worth knowing about.
- Remove entitlements and credentials: delete API keys, SSH keys, OAuth grants and personal access tokens the account created. These often survive account disablement in SaaS platforms.
- Delete: delete after the hold, keeping the audit record. Retention rules for mailboxes and files are applied before deletion, not after.
- Rollback: if a service breaks during the hold, re-enable the account, assign a named owner, record it as a non-human identity and move it to managed credentials. Never simply re-enable and forget.
Exceptions without loopholes
- Break-glass accounts: by design rarely used. Exclude them from automated disablement, but alert on every sign-in and test them on a schedule so the test itself produces a recent, expected sign-in.
- Long leave and seasonal staff: disable rather than exempt, and re-enable on return through a ticket. Keeping an account live for six months of parental leave or an off-season adds risk with no benefit.
- Executives and VIPs: no class exemption. Dormancy in a senior account is as dangerous as anywhere else, and more valuable to an attacker.
- Exception register: each exception has an owner, business reason, compensating control and expiry date no longer than 12 months. Review the register in your access certification cycle. See the Access Reviews Guide.
Non-human accounts: orphaned by default
Service accounts, application registrations and API keys have no HR record, so every one is orphaned unless an owner is recorded. They also defeat simple dormancy rules because they authenticate non-interactively and on schedules.
- Ownership at creation: refuse creation of a service account or application identity without an owner and a consuming system. When the owner leaves, the joiner-mover-leaver process must transfer ownership, not just remove the person.
- Last-used per credential: evaluate each key or secret, not only the account. An account in daily use can still carry an unused second access key.
- Retirement: follow the disable-hold-delete pattern, with the hold monitored for failed authentications that reveal hidden dependencies. See the NHI Offboarding and Decommissioning Guide and How to find and remove stale service principals in Entra ID.
Detection, metrics and framework mapping
Alert on: any successful sign-in by an account correlated to a terminated identity; any sign-in by an account in the quarantine group; re-enablement of a disabled account outside a ticket; and a dormant account suddenly becoming active from a new location or device. ATT&CK tracks this behaviour as T1078 Valid Accounts, including T1078.004 Cloud Accounts, and re-enablement or added credentials as T1098 Account Manipulation.
- Orphan rate: enabled accounts with no valid correlation or owner, as a percentage of all enabled accounts, per system.
- Terminated-but-enabled count: target zero, measured daily.
- Dormancy rate: enabled accounts beyond the threshold for their class.
- Time to disable: median days from termination date, or from crossing the threshold, to disablement.
- Exception register health: exceptions past expiry, target zero.
- Systems in correlation scope: share of in-scope applications aggregated and correlated.
| Framework | Reference | Relevance |
|---|---|---|
| NIST SP 800-53 Rev. 5 | AC-2, AC-2(1), AC-2(3), AC-2(12), PS-4 | Account management, automation, disabling inactive and unassociated accounts, atypical use monitoring, personnel termination |
| NIST CSF 2.0 | PR.AA-01, PR.AA-05 | Identities and credentials managed; access permissions reviewed |
| CIS Controls v8.1 | Safeguards 5.1 and 5.3 | Inventory of accounts; disable dormant accounts after 45 days |
| ISO/IEC 27001:2022 | Annex A 5.18 | Access rights provisioned, reviewed and removed |
| MITRE ATT&CK | T1078, T1078.004, T1098 | Abuse of valid and cloud accounts; account manipulation |
Common failure patterns
- Remote access profiles left behind: in the Colonial Pipeline attack, attackers used a legacy VPN profile that was no longer in use but had never been disabled, and it had no MFA. A single dormant remote access account was enough.
- Leaver processed in core systems only: in the Ledger Connect Kit compromise, a former employee's internal access was removed but their npm publishing access was not, and the attacker who phished them published malicious package versions. External platforms belong in correlation scope.
- Forgotten test environments: the Midnight Blizzard breach began with a password spray against an account in a legacy, non-production test tenant that had no MFA, then a legacy test OAuth application with elevated access. Whole tenants and their applications can become orphaned.
- Trusting attempts as activity: using a last-attempt field so that accounts under attack never cross the dormancy threshold.
- Disable without revoking: disabling the directory account while refresh tokens, personal access tokens and API keys keep working.
- Delete on day one: skipping the hold, breaking an undocumented integration, and teaching the business to resist the next clean-up.
Practitioner checklist
- Define orphaned, uncorrelated and dormant accounts and their time limits in the account management standard (AC-2(3)).
- Write an immutable worker ID to every account at provisioning and correlate on it.
- Bring contractors and service account owners into an authoritative source before tuning anything else.
- Aggregate SaaS, local application, database and remote access accounts, not just the directory.
- Base dormancy on successful sign-in fields and treat null values as unknown, not inactive.
- Set thresholds by account class, with 30 days or less for privileged and remote access accounts.
- Run disable, hold and delete with session and token revocation at the disable step.
- Keep a dated exception register reviewed in access certification.
- Alert on any sign-in by a terminated or quarantined account and on unticketed re-enablement.
- Report orphan rate, terminated-but-enabled count and time to disable monthly.
Standards and references
- NIST: SP 800-53 Rev. 5 (AC-2 Account Management)
- CIS: Controls v8.1 Control 5 Account Management
- Microsoft Learn: How to manage inactive user accounts
- Microsoft Learn: signInActivity resource type
- Microsoft Learn: Last-Logon-Timestamp attribute
- Microsoft Learn: Search-ADAccount
- AWS: Getting credential reports for your AWS account
- Microsoft Learn: Review recommendations for access reviews
Related NHI Mgmt Group resources: Joiner-Mover-Leaver Guide · Employee Offboarding Security Guide · SaaS Deprovisioning Guide · OWASP NHI Top 10 NHI1 Improper Offboarding Guide