Identity Threat Detection & Response (ITDR)
Identity is the new perimeter. In a cloud-native company there is no network edge to defend — every service, every employee, and every workload authenticates, and the attacker's primary goal is to obtain and abuse valid credentials. This file covers detecting identity-based attacks: the defender's view of the attacks documented in authentication/auth-deep-dive.md.
Last verified2026-06
Why Identity Is the Primary Battleground
The classic attacker had to exploit a vulnerability to get in. The modern attacker logs in. Phished credentials, stolen session tokens, and abused OAuth grants are now the dominant initial-access vector because:
- There is no network perimeter to breach in a SaaS + multi-cloud world — the IdP (Okta, Entra ID, Google Workspace) is the front door.
- A valid credential generates legitimate-looking authentication events. The attacker isn't exploiting anything; they're using the system as designed.
- Once inside, identity is how you move: assume a role, mint a token, pivot to the next service.
This is why "ITDR" exists as a named discipline: detecting the abuse of legitimate identity is fundamentally different from detecting malware, because there's no malicious binary — only a login that shouldn't have happened.
The Core Detection Problem
The hard part of identity detection: a malicious login and a legitimate login look almost identical. Both present valid credentials. The signal is almost never the authentication itself — it's the context around it:
- Where from (new country, hosting-provider ASN, anonymizer)?
- When (3am for a 9-5 user)?
- How (new device, headless user-agent, unusual auth method)?
- What happened next (immediately enumerating permissions, accessing crown jewels)?
- Is it physically possible (two logins from continents apart, minutes apart)?
So identity detection is overwhelmingly behavioral and contextual, which makes IdP/audit logs (Okta System Log, Entra sign-in logs, GCP/AWS auth events) your most important data source.
Identity Attacks and How to Detect Each
Credential stuffing & password spraying
stuffing replays leaked username/password pairs; spraying tries a few common passwords across many accounts to stay under per-account lockout thresholds.
spike in failed logins; spraying shows one source IP → many usernames → few attempts each; stuffing shows high failure volume with occasional success. Pivot on source IP/ASN and user-agent. A burst of failures followed by one success from the same source is the high-priority case.
MFA fatigue (push bombing)
the attacker has the password and spams MFA push prompts until the exhausted/confused user approves one.
many MFA challenges in a short window for one user, especially many denials followed by an approval. Also flag approvals where the challenge originated from an anomalous location.
Impossible travel / anomalous location
attacker logs in with stolen credentials from their own location.
two successful logins from locations too far apart for the time elapsed (login in Warsaw, then California 20 minutes later). Tune for VPNs and cloud-IP false positives — corporate VPN egress and mobile-carrier CGNAT generate benign "impossible travel."
Session/token theft (the MFA bypass)
the attacker steals a post-authentication session token (via infostealer malware or an adversary-in-the-middle phishing proxy like Evilginx) and replays it. This bypasses MFA entirely — the token already represents a completed, MFA-satisfied login.
same session/token ID used from two different IPs/devices/ASNs; a session whose device fingerprint or user-agent changes mid-life; token used from a location the original auth didn't come from. This is one of the most important modern detections because MFA does not stop it.
OAuth / consent-grant abuse ("illicit consent grant" / consent phishing)
Last verified2026-06 (audit-log event names below reflect Microsoft Entra and Google Workspace as of this date.)
The mental model to fix first"Sign in with Google" by itself is just authentication — the app learns who you are (scopes openid, email, profile) and nothing else. Consent abuse is about authorization: the app additionally asks for API scopes — gmail.readonly, https://mail.google.com/, drive, or Microsoft Graph Mail.Read, Files.Read.All — plus offline_access. The moment the user clicks Allow, the app receives a refresh token: a long-lived key that lets it call those APIs as the user, indefinitely, with no further login. So the access isn't "the login button" — it's the grant sitting behind it.
So the danger usually isn't a famous app over-asking. It's an attacker-controlled app you've never heard of, and the consent screen you see is the real, genuine Google/Microsoft page — which is exactly what makes it work. You're not being phished for your password; you're being phished for a grant. The attacker never sees the password and never needs it, so MFA and password resets are irrelevant.
The real-world flow
1. Attacker registers an OAuth app with Google/Microsoft, requesting high-risk
scopes (read mail, read files) + offline_access (so it gets a refresh token).
2. Phish: "A document was shared with you — click to view."
The link goes to the LEGITIMATE consent URL, carrying the attacker's client_id.
3. Victim is already logged in, so they just see Google's real consent screen:
"MyDocsViewer wants to: Read your email, See and download your files." → Allow
4. Google redirects an authorization code to the attacker's server, which trades
it for an access token + a refresh token.
5. Attacker now calls the Gmail / Graph API directly with that token: reads mail,
downloads files, creates auto-forwarding rules — with no further user action.Why it's so dangerous — it's stealthy persistence. The grant survives password resets and MFA because there's no login to challenge; the API calls come from a "trusted" third-party app and blend in with normal usage; and no malware ever touches an endpoint. Evicting it requires revoking the grant — the step users and many responders forget.
Real examples
a malicious app literally named "Google Docs" requested contacts + mail scopes and self-propagated by emailing each victim's contacts; it hit on the order of a million accounts in about an hour before Google revoked it.
during the SolarWinds-era intrusions, attackers added their own credentials/secrets to existing OAuth applications and consented malicious apps to obtain persistent, MFA-proof mailbox access.
Variants worth naming
the app is named "Microsoft 365 Security" with a look-alike logo so the consent screen reads as trustworthy.
attackers obtain or spoof the "verified publisher" badge to lower suspicion.
post-compromise, attach a new client secret/certificate to an already-trusted app registration to get long-lived access with no user consent at all.
abuse the OAuth device-authorization flow: the attacker starts it and tricks the user into typing the displayed code into the real login page, handing the attacker the resulting tokens.
Which requested permissions count as abusive (red-flag scopes). Not every scope is equal. The triage rule of thumb: a scope is high-risk when it grants broad read of user data, the ability to send/write/modify, or tenant-wide application access — and the alarm escalates when it's an application permission (acts without any signed-in user) or paired with offline_access (a refresh token for permanent access). Concrete tiers:
| Risk | Microsoft Graph (M365) | Google Workspace | Why it's dangerous |
|---|---|---|---|
| Critical | Mail.ReadWrite, Mail.Send, MailboxSettings.ReadWrite (inbox rules → silent forwarding); Files.ReadWrite.All, Sites.ReadWrite.All; Directory.ReadWrite.All, RoleManagement.ReadWrite.Directory (grant itself admin); Application.ReadWrite.All (mint new app secrets = self-persistence); full_access_as_app | https://mail.google.com/ (full Gmail), gmail.send, gmail.settings.basic (forwarding/filters); drive (full Drive); admin.directory.user, admin.directory.group | Read and write/send, or directory/admin control. Lets the attacker read everything, exfiltrate, send phishing as the victim, set hidden auto-forward rules, and escalate. |
| High | Mail.Read, Files.Read.All, Sites.Read.All, Notes.Read.All, Chat.Read, User.Read.All | gmail.readonly, drive.readonly, contacts, calendar | Broad read of mail/files/contacts across the user (or all users) — quiet bulk exfiltration even without write. |
| Watch the modifier | *.All = across the whole tenant, not just the user; application permissions (no user context) > delegated; anything plus offline_access | domain-wide delegation; .../auth/ scopes spanning all users | .All + application + offline_access is the worst trio: tenant-wide, unattended, and permanent. |
| Usually benign | openid, email, profile, User.Read (just the signed-in user) | openid, email, profile | Identity only — this is plain "Sign in with", not data access. |
Two more tells independent of the scope name: an app whose requested scopes don't match what it claims to do (a "PDF viewer" asking for Mail.Send), and any app requesting admin-restricted / admin-consent-required permissions, which by design only a privileged admin can approve — so a consent prompt for one is a moment to stop and verify.
audit the consent/grant log, not the sign-in log. In Microsoft Entra/M365 the operations are "Consent to application", "Add OAuth2PermissionGrant", "Add app role assignment to service principal", and "Add service principal credentials" (the secret-injection tell); in Google Workspace it's the Token / OAuth app activity audit. Hunt for: consent to unverified publishers requesting high-risk scopes; an app holding mail/file scopes with a tiny user count; redirect/reply URLs that don't match the app's stated identity; and consent spikes across many users in a short window (a phishing campaign landing).
revoke the grant (not just reset the password — a reset does nothing to a delegated token), then restrict end-user consent so high-risk scopes require admin approval (the admin-consent workflow) and allowlist trusted apps. An admin can and should revoke on the user's behalf — in incident response you never wait for the user to click anything.
How to actually revoke a grantThe critical catch: revoking the consent does not invalidate tokens already issued. Three steps, all needed — (1) remove the grant/consent, (2) revoke the user's refresh tokens/sessions, (3) disable or delete the app so it can't request new tokens. Access tokens already minted (typically valid ~1 hour) usually can't be individually revoked, so disabling the app is what stops new ones from being issued. Where each is done:
Entra admin center → Enterprise applications → select the app. To cut everyone off at once, set Properties → "Enabled for users to sign in?" = No (or delete the enterprise app, which removes the service principal and its grants). To revoke a single user's delegated consent, delete its oauth2PermissionGrant — Microsoft Graph DELETE /oauth2PermissionGrants/{id}, or PowerShell Remove-MgOauth2PermissionGrant. Then revoke that user's tokens with Revoke-MgUserSignInSession (the revokeSignInSessions action), which invalidates refresh tokens. Users can self-service at myapps.microsoft.com → Manage your apps, but IR does it centrally.
Admin console (admin.google.com) → Security → Access and data control → API controls → Manage Third-Party App Access. Set the offending app to Blocked — that revokes its OAuth tokens for all users at once. To target one user, Directory → Users → user → Security → Connected applications and remove access. The user's own self-service page is myaccount.google.com/permissions.
revoke a user's OAuth grants via the Admin console or the API — GET /api/v1/users/{userId}/grants to list, DELETE to revoke all (or a specific grant) — then clear the user's sessions/tokens and deactivate the app integration so it can't re-issue.
Privilege escalation & role assumption
after getting a foothold identity, escalate — add self to an admin group, assume a more powerful cloud role, create a new access key.
changes to high-privilege group membership; AssumeRole chains into sensitive roles; new long-lived credentials (access keys, service-account keys) created; an account using a permission it has never used before.
Federation / SSO trust abuse (Golden SAML and friends)
The trust model firstIn SAML single sign-on, the identity provider (IdP) — Okta, ADFS, Entra ID — authenticates the user and hands back a signed assertion: an XML statement like "this is alice, an admin, valid for one hour," signed with the IdP's private signing key. The service provider (SP) — AWS, Salesforce, Google Workspace — doesn't phone home to check; it simply verifies the signature against the IdP's public certificate it has on file. Whoever controls a trusted signing key can mint a valid assertion for any user, any privileges, any lifetime — no login, no password, no MFA. That is Golden SAML; it's the SAML analogue of a Kerberos Golden Ticket (forging tickets with the krbtgt key).
There are two ways to get a trusted signing key, and the distinction matters:
| Steal the key (classic Golden SAML) | Add your own key (cloud-IdP version) | |
|---|---|---|
| Where the key lives | On-prem ADFS server you run | With the SaaS vendor (Okta, Entra ID) — not extractable from your tenant |
| What the attacker needs | Control of the ADFS box | IdP admin rights in your tenant |
| How | Extract the token-signing key (e.g. ADFSDump pulls the encrypted key and the DKM master key from AD; ADFSpoof forges) | Register a key they control as trusted: a rogue federated domain or second token-signing cert in Entra ID (the AADInternals technique, forging via immutableID), or a malicious inbound federation / SAML app in Okta |
| Seen in the wild | APT29 / "Nobelium" in the SolarWinds intrusion, pivoting from on-prem into M365 | Common after IdP-admin compromise; IdPs themselves are also targeted |
| The door | "Steal their key" | "Make my key trusted" |
Coined by CyberArk in 2017, the name echoes Kerberos Golden Tickets, which forge tickets with the krbtgt key.
-
Obtain a trusted signing keyAttacker
Steal the ADFS key, or add a rogue federation or signing cert in the cloud IdP.
-
Forge assertions for any user, any role, any lifetimeAttacker
No login, no password, no MFA: the service provider only checks the signature. A skeleton key for the whole SSO estate.
-
Correlate SP sign-ins with IdP issuanceDetect
A successful AWS or Salesforce login with no matching IdP sign-in event; assertions with odd lifetimes or an unexpected signing cert; a new federated domain or token-signing certificate appearing in the tenant.
-
Rotate the signing key and remove rogue trustsRespond
Password resets and MFA re-enrolment do nothing here. Rotate the token-signing certificate (twice for ADFS, to flush the old one) and delete any federation the attacker added.
Memory hookGolden SAML = forging SAML assertions with a trusted signing key. Classically by stealing the ADFS key; in the cloud, more often by adding your own trusted key after compromising an IdP admin.
Dormant & service accounts
attackers love accounts nobody watches — dormant employee accounts and non-human service accounts that never trigger "unusual for this user" because nobody knows what usual is.
any activity on an account dormant for N days; service accounts authenticating interactively (they shouldn't), from new IPs, or doing things outside their narrow defined purpose. Baseline non-human identities tightly — they're predictable, so deviation is a strong signal.
Non-Human Identity (NHI) — the fast-growing surface
Machines now vastly outnumber humans as authenticating identities: service accounts, API keys, OAuth tokens, cloud workload identities, CI/CD credentials. They're attractive because they're often over-privileged, long-lived, poorly inventoried, and unmonitored.
Detection leans on the fact that machines are predictable: a service account should call the same APIs, from the same hosts, on the same schedule. So deviation is unusually meaningful — a CI credential that suddenly enumerates IAM, or a workload identity authenticating from outside its normal subnet, is a strong signal precisely because legitimate machine behavior is so consistent.
UEBA: behavioral baselining for identity
User & Entity Behavior Analytics builds a per-identity baseline of "normal" — typical login times, locations, devices, data-access volume, and API usage — then scores deviations. It's how you catch the valid login that's anomalous for that specific user, which static rules miss.
The tradeoff: UEBA reduces missed novel attacks (better recall) but generates false positives when normal behavior legitimately changes (travel, role change, new project). It's best used to prioritize and enrich rather than to auto-page — an anomaly score feeding human triage, not a standalone high-severity alert.
Response Actions for Identity Compromise
Detection is half the discipline; the "R" in ITDR is the response. For a confirmed identity compromise, revoking the session is as important as resetting the password — because of token theft, a password reset alone leaves stolen tokens valid:
(the step people forget — kill the stolen token, not just the password).
and rotate any keys the identity could access.
the account approved.
the account pending investigation.
what did this identity touch, assume, or create while compromised?
Interview Questions
In a SaaS and multi-cloud world there's no network edge to defend — every service, employee, and workload authenticates to an identity provider, so the IdP is effectively the front door. Attackers have shifted accordingly: instead of exploiting a vulnerability to get in, they log in with phished credentials, stolen session tokens, or abused OAuth grants. That's harder to detect than malware because a valid credential produces legitimate-looking authentication events — there's no malicious binary, just a login that shouldn't have happened. So defense centers on the IdP and audit logs, and detection becomes behavioral and contextual.
Two main ways. MFA fatigue — they have the password and spam push prompts until the user approves one; detect by alerting on many MFA challenges for one user in a short window, especially denials followed by an approval. And session-token theft, which is the bigger problem — using an infostealer or an adversary-in-the-middle proxy like Evilginx, they steal the post-authentication token, which already satisfies MFA, and replay it. MFA doesn't stop that at all. I detect it by looking for the same session or token ID used from two different IPs, devices, or ASNs, or a session whose device fingerprint changes mid-life. And critically, response has to revoke the session, not just reset the password, or the stolen token stays valid.
The attacker tricks a user into granting a malicious OAuth application broad scopes — read mail, read files. Once granted, the app holds token-based access that's persistent and, crucially, survives password resets and MFA, because there's no login to block — it's a delegated grant. It's a stealthy persistence mechanism. I detect it in the consent/grant audit log, not the sign-in log: new consents to unverified apps requesting high-risk scopes, consent spikes across many users indicating mass phishing, and unrecognized apps holding mail or file scopes. Response is to revoke the grant, not reset the password.
Service accounts are non-human identities, which makes them easier in one way: they're highly predictable. A given service account should call the same set of APIs, from the same hosts, on the same schedule, for one narrow purpose. So I baseline that tightly and alert on deviation — the account authenticating interactively when it never should, from a new IP or subnet, calling APIs it's never used, or a sudden burst of enumeration like List and Describe calls. The challenge is they're often over-privileged, long-lived, and poorly inventoried, so the first task is often just knowing they exist and what normal looks like. Deviation from a consistent machine baseline is a stronger signal than the equivalent for a human.
Golden SAML is when an attacker compromises the identity provider's SAML signing key and forges authentication assertions directly. Because they control the signing key, they can mint a valid assertion for any user, with any privileges, without ever touching the IdP's actual login flow — it's a skeleton key for the entire SSO estate, and it bypasses MFA and password policies entirely. It was central to major supply-chain intrusions. It's hard to detect because the forged assertions look valid to service providers; the way to catch it is correlation — looking for authentications at a service provider that have no corresponding issuance record on the IdP side, or assertions signed by an unexpected certificate or with anomalous lifetimes. The real defense is protecting the signing key in the first place.