OAuth Consent — Persistent Mailbox Access Granted
A user granted Mail.Read, User.Read, and Offline_access to a commercial third-party AI application. Offline_access creates a persistent refresh token outside MFA enforcement — the highest-risk OAuth scope in M365. Consent IP confirmed as clean Microsoft OAuth infrastructure, confirming legitimate user action rather than consent phishing. Client revoked access and initiated a tenant consent policy review.
OAuth 2.0 application consent attacks — also termed illicit consent grants — are a recognised Microsoft 365 attack vector in which threat actors register malicious Azure AD applications and trick users into granting them access to Microsoft 365 data. In this incident, the application is a legitimate commercial product, not a malicious actor-created app. However, the permissions granted create a persistent data access channel that represents a material security risk regardless of the application's legitimacy.
The Offline_access scope is particularly sensitive: it enables the application to obtain a long-lived refresh token that can be exchanged for access tokens repeatedly without user interaction or MFA re-authentication. The refresh token persists beyond the active session, is not disrupted by session expiry, and in some configurations survives a password change. This effectively creates a backdoor into the user's mailbox that the user is unlikely to be aware of unless they explicitly review their Azure AD consent grants.
Azure AD's default tenant configuration permits users to consent to third-party applications without administrator approval. This is widely recognised as a systemic risk: any user in the tenant can grant any application persistent access to their mailbox data without IT oversight. Changing this single configuration to require admin approval closes the entire illicit consent grant attack surface.
The OAuth consent event occurred at 20:34 UTC on a weekday evening. The source IP was identified as clean Microsoft infrastructure, consistent with the OAuth consent being processed through Microsoft's authentication portal (login.microsoftonline.com). This rules out session hijack or attacker-controlled consent flow — the consent was made by a legitimate user via the application's 'Sign in with Microsoft' flow.
The user's 30-day sign-in baseline showed 201 sign-ins from a single consistent London IP — an exceptionally stable pattern indicative of a fixed home-working or office-based user. The consent event from a Microsoft IP is expected for OAuth flows and is not anomalous in itself.
The three permissions granted carry distinct individual risk profiles: User.Read provides low-risk basic Azure AD profile information. Mail.Read provides high-risk full read access to the entire contents of the user's Exchange mailbox — all sent and received mail, attachments, calendar invites, and contact information. Offline_access provides critical-risk capability: it enables the application to obtain a refresh token that persists beyond the active session, allowing the application to continue requesting Mail.Read access tokens without the user being present and without triggering MFA re-authentication.
The combination of Mail.Read and Offline_access represents a persistent, MFA-bypassing mailbox access channel. The access remains active as long as the consent grant exists and the refresh token has not been revoked — it does not expire with the user's session and is not visible to the user unless they explicitly review their Azure AD consent grants in the My Apps portal.
Non-interactive sign-ins were checked to assess whether the application had already initiated token exchange post-consent. Tenant-wide consent audit reviewed all offline_access grants in the last 90 days — identifying whether other users had made similar grants under the default consent configuration.
| Type | Indicator | Notes |
|---|---|---|
| Application | Third-party AI Application (commercial — name redacted) | Legitimate app — risk is in the permissions granted, not the application itself |
| Permissions | Mail.Read, User.Read, Offline_access | Mail.Read + Offline_access = persistent MFA-bypassing mailbox access channel |
| Consent IP | [MSFT_INFRA_IP] | Clean Microsoft infrastructure — OAuth consent portal (login.microsoftonline.com) |
| User Baseline | 201 sign-ins from single consistent IP | Extremely stable pattern — confirms consent event was a genuine user action |
| Critical Risk | Offline_access refresh token | Persists beyond session; outside MFA enforcement; survives password change in some configurations |
| Tactic | Technique | ID | Observed |
|---|---|---|---|
| Initial Access | Valid Accounts / Consent Phishing | T1078.004 / T1566 | User-granted OAuth consent — legitimate user action with excessive permissions |
| Persistence | Account Manipulation: Additional Cloud Credentials | T1098.001 | Refresh token from Offline_access = persistent credential beyond active session |
| Collection | Email Collection: Remote Email Collection | T1114.002 | Mail.Read enables full remote mailbox content access by third-party |
| Defense Evasion | Use Alternate Authentication Material | T1550 | Refresh token operates outside MFA enforcement — cannot be blocked by MFA policy alone |
// Confirm consent event details and source IP
AuditLogs
| where TimeGenerated > ago(30d)
| where OperationName == "Consent to application"
| where InitiatedBy.user.userPrincipalName == "[USER_UPN]"
| project TimeGenerated, TargetResources, InitiatedBy, Result, AdditionalDetails
// Check for non-interactive sign-ins (refresh token usage post-consent)
SigninLogs
| where UserPrincipalName == "[USER_UPN]"
| where AppDisplayName contains "[APP_NAME_REDACTED]"
| where SignInEventTypes contains "nonInteractiveUser"
| project TimeGenerated, AppDisplayName, IPAddress, ResourceDisplayName, AuthenticationRequirement
// CRITICAL: Tenant-wide audit — all offline_access consents in last 90 days
AuditLogs
| where TimeGenerated > ago(90d)
| where OperationName == "Consent to application"
| where TargetResources has "offline_access"
| project TimeGenerated, InitiatedBy, TargetResourcesThis is one of the highest-impact alert types in an M365 environment when it goes undetected. The persistence mechanism (refresh token from Offline_access) means the access channel continues long after the user has forgotten they granted it.
The escalation decision was straightforward — Mail.Read + Offline_access from any application warrants investigation regardless of reputation. The tenant-wide KQL query is the most critical investigative step: one alerted user may mean many others who consented silently.
The most impactful single recommendation: restrict user-level consent to require admin approval. This immediately closes the illicit consent grant attack surface for the entire tenant.