OAuth Abuse in SaaS: The Attack Moved to the Authorization Layer — Your Detection Didn't
OAuth abuse bypasses MFA by attacking authorization, not authentication. Most SOCs don't collect consent-grant telemetry — here's what to detect.
Your SOC is watching the door. Password, MFA prompt, impossible travel, new device, off-hours login — the entire identity-detection stack is built to catch someone trying to authenticate as a user they’re not.
OAuth abuse doesn’t go through the door. It goes through the API, with a valid token the user handed over voluntarily. No password is stolen, no MFA prompt is answered, no login anomaly fires — because the attack never touches authentication at all. It targets the layer one step past it: authorization. And that layer is the one most detection programs don’t instrument.
This is not a fringe technique. It was the defining breach pattern of 2025. The Salesloft Drift compromise rode stolen OAuth tokens into 700-plus organizations [1], with researchers estimating a blast radius roughly 10 times larger than prior supply-chain incidents — I covered why that compromise was invisible to identity detection in the NHI post. This post is about the broader class it belongs to, and what actually fires.
Why It’s Invisible
Walk the credential-focused detection stack against an OAuth consent attack and you get the same answer at every step: nothing.
- MFA — not involved. Consent happens after authentication; the user is already logged in when they approve the app. MFA already passed.
- Password reset — irrelevant. The token is independent of the password. Reset the credential and the granted token keeps working until it’s explicitly revoked.
- Impossible travel / new device — the attacker isn’t logging in. They’re replaying a token against an API, often from infrastructure that looks like a normal integration.
- Brute force / spray — there’s nothing to guess. The access was granted.
This is the same structural blindness I described in the NHI post, where every human-behavior detection primitive returns null against a non-human identity. An OAuth grant is a non-human identity — a token acting on the user’s behalf — and the credential-centric stack has nothing pointed at it. The guidance the industry keeps repeating after each of these breaches is the tell: stop relying on credential-focused defenses and get visibility into OAuth grants, connected applications, consent activity, and token usage. That visibility is telemetry most SOCs don’t collect today.
The Attack Taxonomy
“OAuth abuse” is a family, not a single technique. The variants share a target — the authorization layer — and differ in how they get the grant.
Illicit consent grant (consent phishing). The classic. The victim gets an OAuth consent screen for a third-party app requesting access to their mailbox, files, or profile. They click Accept. The app now holds a token with whatever scopes it asked for. Because it targets authorization, it bypasses MFA and survives a password reset. This is cataloged as T1528, Steal Application Access Token.
The consent worm. Once an app holds a mailbox token, it can spread. Reported “consent virus” patterns use the granted token to read the victim’s frequent contacts and send personalized consent invites from the victim’s own address — self-propagating across an organization, with reports of a single department fully infected in under 15 minutes. The lateral movement happens entirely at the authorization layer, from a trusted internal sender.
Device-code phishing. The attacker calls the victim posing as IT, and walks them through entering a device code on a legitimate vendor sign-in page — authorizing what looks like the vendor’s own first-party app. There’s no malicious-looking app to spot, because the app is real. This was abused hard enough against Salesforce that Salesforce removed OAuth 2.0 device flow entirely in September 2025.
ConsentFix. A newer variant that social-engineers users into copying and pasting valid sign-in URLs, granting access without ever capturing a password or MFA code.
Token theft and replay. Skip the user entirely — steal the token from a compromised integration and replay it. Salesloft Drift is the canonical case: valid integration tokens, replayed across hundreds of downstream tenants, indistinguishable from legitimate API traffic.
Different front doors. Same result: a valid token, held by an attacker, operating inside your trust boundary with no authentication event to flag.
”Isn’t This a User-Awareness Problem?”
The obvious objection: this is a phishing problem, so the fix is user training and email security — teach people not to click Accept on a consent screen, and the attack dies. Detection is treating the symptom.
That objection underestimates how the attack is built. Consent phishing is specifically designed to defeat the trained instinct. The consent screen is a real Microsoft or Google screen, served from the real identity provider over a legitimate URL — none of the cues you train users to look for are present, because nothing about the page is fake except the intent of the app behind it. Device-code phishing goes further and authorizes the vendor’s own first-party app, so even a careful user is approving something genuine. And here’s the part awareness can’t touch: once consent is granted, the token persists. Training reduces the rate of bad clicks. It does nothing about the ones that get through, and it does nothing after the grant exists.
The strongest evidence that awareness is insufficient is what the vendors did. Salesforce didn’t respond to device-code phishing with a training campaign — they removed the device flow entirely, because they concluded the flow could not be made safe by asking users to be careful. When the platform owner pulls a feature rather than rely on awareness, “just train the users” is not a detection strategy. Awareness is a prevention layer. Detection is the backstop for everything that gets past it — and with this attack class, a meaningful amount always does.
What to Detect
The good news: the authorization layer is highly observable if you collect the logs. The grant is an event, and unlike a stolen password, it’s recorded in your identity provider’s audit trail. The reason these attacks succeed isn’t that they’re undetectable — it’s that the telemetry sits uncollected. Microsoft Defender ships an illicit-consent-grant detection; Elastic ships prebuilt rules for “Illicit Consent Grant via Registered Application” and “OAuth Illicit Consent Grant by Rare Client and User.” This is the same gap I described in The Detection Funnel: the capability exists, it’s just not deployed. Adoption gap, not capability gap.
The high-signal events live in the Entra ID / M365 audit log:
Consent to applicationandAdd OAuth2PermissionGrant— a user or admin granting an app delegated access.Add app role assignment grant to service principal— application-level (not delegated) permissions, often the higher-privilege path.- The scopes are where the signal concentrates.
offline_access(refresh tokens — persistence),Mail.Read/Mail.ReadWrite,Files.ReadWrite.All,full_accessare the ones worth waking up for. Admin consent and tenant-wide delegation raise severity sharply, because one grant covers every user.
The honest problem is false positives from legitimate SaaS sprawl — every team wires up a new app, and you don’t want to alert on all of them. Three things scope it down:
- Risky scope, not any scope. Most legitimate grants ask for narrow read scopes. Filter to the dangerous set above and the volume drops hard.
- Rare client + rare user. A first-seen app ID consented by a user who has never granted consent before is a far stronger signal than a known marketplace app onboarded by IT. The “rare client and user” framing is exactly what the prebuilt rules key on.
- Correlate to the admin-consent workflow. Legitimate app onboarding goes through a request-and-approve path. A grant that didn’t is the out-of-band grant pattern from Identity Creep — privileged access added off the approved path.
# Detection rationale: an illicit consent grant gives an attacker-controlled app
# a token with delegated access to mail/files — bypassing MFA and surviving
# password resets, because it targets authorization, not authentication. High
# signal when scoped to dangerous scopes granted to a rarely-seen application;
# legitimate app onboarding is high-volume but narrow-scoped and goes through
# the admin-consent workflow, so it filters out.
title: Illicit OAuth Consent Grant — Risky Delegated Scope to Rare App
status: experimental
logsource:
product: azure
service: auditlogs
detection:
selection:
operationName:
- 'Consent to application'
- 'Add OAuth2PermissionGrant'
target_scopes|contains:
- 'offline_access'
- 'Mail.Read'
- 'Mail.ReadWrite'
- 'Files.ReadWrite.All'
- 'full_access'
filter_known_apps:
# allowlist reviewed/approved enterprise app IDs onboarded via IT
targetResources.id:
- '<approved-app-id-1>'
- '<approved-app-id-2>'
condition: selection and not filter_known_apps
falsepositives:
- IT-approved app onboarding via the admin-consent workflow (correlate to the
approval request and allowlist the app ID)
- Established marketplace integrations re-consenting after a scope update
level: high
tags:
- attack.credential_access
- attack.t1528
- attack.persistence
- attack.t1550.001
The grant event is the cheapest win, but it only catches the consent-phishing class. Token theft — Drift — produces no consent event, because the grant already existed and was legitimate. For that class, two more detection surfaces matter, and both sit on telemetry you have to deliberately build.
Connected-app inventory. You cannot detect an anomalous app if you don’t know which apps hold tokens in your tenant. The inventory is the baseline, and it’s also the cheapest piece of governance value in this whole space: a periodic pull of every enterprise app, its grant date, its scopes, its last-used timestamp, and its consenting user. Most tenants have never produced this list. When they do, the first run is usually alarming — dozens of apps with mailbox access that nobody can account for, half of them last used never. That list is both your detection baseline and your revocation backlog.
Token-usage anomaly. A stolen token doesn’t change its scopes; it changes its behavior. An integration that historically reads three object types and a few hundred records suddenly enumerating thousands across the tenant is the Drift pattern exactly — and it’s the same per-principal, scope-expansion baseline I argued for in the NHI post: deviation from what that specific token normally does, not from what a human would do. This is the hardest of the three to build because it needs a behavioral baseline per integration, but it’s the only one that catches a valid token being used by the wrong hands. The grant looked normal. The volume didn’t.
The Token Is Standing Privilege
Here’s the part that outlives the incident. An OAuth grant doesn’t expire when the phishing campaign ends or the attacker’s session closes. It’s a refresh token sitting in your tenant, valid until someone explicitly revokes it — and most organizations have no process that ever does.
That makes every connected app a piece of standing privilege, in exactly the sense I described in Identity Creep: access that accumulates and never gets removed, until someone finds the part you forgot about. A granted OAuth token is also a non-human identity with no human owner — and improper offboarding of non-human identities is the single most common way these grants rot into latent breach risk. The grant you should have revoked eight months ago is indistinguishable from the one you use daily, right up until it’s replayed.
So the program-level fix is the same one the rest of the identity series keeps landing on: treat connected apps as privileged access with a lifecycle. Inventory them. Review consent grants the way you’d review admin role assignments. Revoke on a schedule and on offboarding. Detection tells you when a dangerous grant happens; governance decides whether the token should still exist next quarter. You need both, and the detection half is the one your SOC owns.
The same token-theft logic plays out one layer down, in the cloud control plane, where the stolen credential belongs to a compute workload rather than a SaaS app — I cover that in Workload Identities Have a Home Address.
Closing
The attack surface moved. Identity-based intrusion used to mean stealing a credential and authenticating as someone else, and the entire detection stack grew up to catch exactly that. OAuth abuse skips it — it asks the user to grant access, or steals a token that was already granted, and operates at a layer where MFA, password policy, and login anomalies have nothing to say.
Two questions tell you whether you can see it. When an app is granted mailbox access in your tenant, does anything fire? And do you have an inventory of every token already holding access — and a process that ever revokes one?
If the answer is no, you’re guarding the door while the API stays open. And as SaaS-to-SaaS integrations and AI agents multiply the number of things asking for consent, that open API is going to be the most common way in — not the second-most. The detection isn’t exotic. The telemetry is sitting in your identity provider’s audit log right now, waiting for someone to turn it into an alert.
Resources
- Widespread Data Theft Targets Salesforce Instances via Salesloft Drift — Google Threat Intelligence Group (UNC6395; stolen Drift OAuth tokens used to export data from 700+ Salesforce tenants).