NIST SP 800-53 Rev. 5 · Access Control
AC-2(3) on Microsoft Sentinel
Stale privileged access — a published KQL query you can run against Microsoft Sentinel / Log Analytics, with the evidence it needs, the settings you decide, and what a result does and does not establish.
Why this matters
An administrator account nobody has used in months, still holding full powers
Administrative access tends to be granted for a project, a migration, or an emergency, and then never withdrawn. The person moved to another team, or the work finished, but the account keeps its powers. It is not being used, which is exactly why nobody notices it — and an unused account with full powers is a quiet prize for anyone who obtains its password.
Why this check earns its place. Dormancy is the signal. An administrator using their access daily is doing their job; one who has not signed in for months almost certainly does not need the access, and the check reports the second without pestering the first.
- What it reads
- The organization's list of who holds administrative roles, compared against its record of who has actually signed in.
- What it reports
- Accounts holding administrative powers that nobody has signed into for longer than the organization allows.
See related public disclosures on the Signals page →
What this finds
Privileged role held by an identity with no successful authentication inside the inactivity threshold.
The requirement
The organization must disable accounts within an organization-defined time period when the account has been inactive for an organization-defined period, has expired, or is no longer associated with a user or role.
NIST SP 800-53 Rev. 5 — AC-2(3) (Account Management | Disable Accounts).
NIST requires inactive accounts to be disabled within a defined period but does not set the period. The 90-day threshold, the definition of privileged, and break-glass exclusions are local parameters.
How this maps to the CISA performance goals
The Cross-Sector Cybersecurity Performance Goals are a voluntary baseline published by CISA — the U.S. federal agency for critical-infrastructure cybersecurity — written for organizations too small to employ security staff. This control speaks to:
- 3.H — Implement the principles of least privilege
Privileged accounts left in place beyond their use are a standing violation of least privilege. - 3.D — Revoke credentials for departing staff (partial — see note)
Overlaps only where the stale account belongs to someone who has left. Staleness is the broader condition.
See the full coverage map, including the goals no query can answer →
Evidence this query needs
Privileged role register privileged_role_register.csv
Defines which roles your organisation treats as privileged, who owns each one, and how often it must be reviewed. Cloud platforms know which roles exist; only you know which ones matter and who is accountable for them.
Minimum fields: role_name, platform, privilege_classification
Three fields make the staleness and MFA checks work. The ownership fields are what make AC-6(7) answerable at all — without them that check has nothing to test against.
The query
Published as ac-2-3-stale-privileged.azure.kql. Reads IdentityInfo (UEBA), SigninLogs, PrivilegedRoleRegister (watchlist). Requires: Log Analytics Reader; Sentinel Reader for watchlists.
Before this returns anything,
IdentityInfo (UEBA), SigninLogs have to be reaching Microsoft Sentinel / Log Analytics, and PrivilegedRoleRegister (watchlist) has to be landed there. If not, the query reports nothing found — which looks
exactly like nothing wrong. What has to be switched on first →
// AC-2(3) -- privileged identities with no recent successful sign-in
let StaleDays = 90;
let PrivRoles =
_GetWatchlist('PrivilegedRoleRegister')
| where platform =~ "azure"
| where tobool(break_glass) != true
| project RoleName = tostring(role_name);
IdentityInfo
| where TimeGenerated > ago(1d)
| summarize arg_max(TimeGenerated, *) by AccountUPN
| mv-expand AssignedRole = AssignedRoles to typeof(string)
| where AssignedRole in (PrivRoles)
| project UserKey = tolower(AccountUPN), AccountDisplayName,
AssignedRole, SourceSystem = "Microsoft Entra ID"
| join kind=leftouter (
SigninLogs
| where TimeGenerated > ago(180d)
| where ResultType == 0
| summarize LastSignIn = max(TimeGenerated)
by UserKey = tolower(UserPrincipalName)
) on UserKey
| extend DaysIdle = iff(isnull(LastSignIn), 999,
datetime_diff('day', now(), LastSignIn))
| where DaysIdle > StaleDays
| project UserKey, AccountDisplayName, AssignedRole,
SourceSystem, LastSignIn, DaysIdle
| order by DaysIdle desc
Open this pack on Microsoft Sentinel to adjust the settings and download it →
The interactive version opens on Microsoft Sentinel — the platform on this page — even if your environment profile does not list it.
Settings you decide
NIST states the objective and leaves these to your organization. The interactive version of this pack applies them to the query for you.
- Inactivity threshold (days) (default 90)
- Privileged identities with no successful sign-in in this many days are reported.
- Sign-in history window (days) (default 180)
- Must exceed the inactivity threshold, or the query cannot distinguish dormancy from absent data.
- Limit to specific accounts (optional)
- Paste user principal names, one per line.
Running it continuously
Sentinel scheduled analytics rule
Rule type: Scheduled query rule
Run frequency: Every 24 hours
Lookup period: Last 180 days
Trigger: Number of query results > 0
Entity mapping: Account -> UserKey
Severity: Medium
Incident: Create incident, group by Account entity
Suppression: 7 days per matched account
Runs daily rather than hourly: dormancy changes slowly, and a 7-day suppression stops the same idle account re-alerting during review.
What a result does not prove
Inactivity alone does not establish that access is unnecessary. Missing activity may reflect licensing, retention limits, non-interactive use, or an authentication path outside the queried source.
Validation status for this platform: Not tenant-validated. Structure, query generation, and preflight are covered by the project's automated test suites. This pack has not been executed against a live tenant, account, or index. Validate it in a non-production scope before relying on any result.
Before you act on a result
- Is this a human, service, break-glass, or seasonal identity?
- Is authentication history complete and retained for the full review window?
- Does the identity authenticate through a path this data source does not capture?
- Is the elevated role still required for current responsibilities?
Common questions
- How do I check for stale privileged access in Microsoft Sentinel?
- Run the published KQL query on this page against Microsoft Sentinel / Log Analytics. It reads IdentityInfo (UEBA), SigninLogs, PrivilegedRoleRegister (watchlist) and reports: Privileged role held by an identity with no successful authentication inside the inactivity threshold.
- What permissions are needed to run this Microsoft Sentinel query?
- Log Analytics Reader; Sentinel Reader for watchlists.
- What evidence does AC-2(3) need that Microsoft Sentinel cannot produce?
- Privileged role register (privileged_role_register.csv). Defines which roles your organisation treats as privileged, who owns each one, and how often it must be reviewed. Cloud platforms know which roles exist; only you know which ones matter and who is accountable for them. At minimum it must carry: role_name, platform, privilege_classification.
- Does a result from this query mean the control has failed?
- Inactivity alone does not establish that access is unnecessary. Missing activity may reflect licensing, retention limits, non-interactive use, or an authentication path outside the queried source.
Terms used on this page
- NIST SP 800-53the U.S. federal catalogue of security requirements
- The catalogue of security and privacy requirements published by the National Institute of Standards and Technology, a U.S. federal agency. U.S. government systems are measured against it, and many private organizations adopt it voluntarily. Each requirement has an identifier such as AC-2. Official source →
- CISACybersecurity and Infrastructure Security Agency
- The U.S. federal agency responsible for national critical-infrastructure cybersecurity. Its publications are works of the U.S. government and are free to use. Official source →
- KQLKusto Query Language
- The language used to ask questions of data held in Microsoft Sentinel. A query written in it is text, like a spreadsheet formula, and can be read before it is run.
- CPGCross-Sector Cybersecurity Performance Goals
- A voluntary baseline of security practices published by the U.S. Cybersecurity and Infrastructure Security Agency, written specifically for organizations too small to employ security staff. It is a short, plainly written starting list rather than a full standard. Official source →
- not tenant-validatednever executed against real data
- The check has passed the project's automated tests for structure and syntax, but has never been run against real data anywhere. Test it in a safe scope before relying on any result.
The same control on other platforms
- AC-2(3) on AWS — SQL (Athena) + Lambda
- AC-2(3) on Splunk — SPL
- All platforms for AC-2(3)