Incident ReportsIR
IR-2025-008
MED

OAuth Consent — Persistent Mailbox Access Granted

FILED:Oct 2025
TAXONOMY:T1098.001
Complexity:Moderate
~21h containment
~6m read
TRUE POSITIVE — ACCESS REVOKED, POLICY REVIEW INITIATED

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.

OAuthIdentityEntraM365Consent
Outcome
OAuth consent grant revoked — refresh token invalidated, persistent access channel closed
Client confirmed policy review underway — consent policy change to require admin approval
Persistent mailbox access channel closed
Background & Context

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.

Triage Thought Process
01Confirm the consent IP before anything else. Non-Microsoft IP = potential attacker-controlled consent flow (consent phishing). Microsoft infrastructure IP = legitimate user action confirmed.
02Risk-assess each permission independently. User.Read = low. Mail.Read = high (full mailbox read). Offline_access = critical (persistent MFA-bypassing refresh token).
03The application being legitimate does not reduce the risk. Mail.Read + Offline_access creates a persistent data access channel regardless of the application's trustworthiness.
04Check whether the refresh token was already being used. Query for non-interactive sign-ins from the consented application after the consent event timestamp.
05Check the tenant consent configuration. Default Azure AD settings permit user-level consent — this is a systemic attack surface across the entire tenant.
06Escalate for access revocation. Revocation of the OAuth consent grant invalidates the refresh token — the definitive containment action.
07Conduct a tenant-wide audit. One alerted user under default consent settings may mean many others consented silently.
Decision
Escalate — Mail.Read + Offline_access from any application warrants investigation and revocation regardless of the app's reputation. Policy change to require admin consent is the required systemic fix.
Incident Timeline
16 Oct, 20:34
User grants OAuth consent: Mail.Read, User.Read, Offline_access to third-party AI application
16 Oct, 20:34
Azure AD audit log records consent event from Microsoft OAuth infrastructure IP
16 Oct, ~21:00
Alert generated in Microsoft Sentinel: Suspicious application consent for offline access
17 Oct, ~08:00
Analyst begins triage — alert reviewed, ticket opened
17 Oct, ~08:10
Consent IP enriched: clean Microsoft cloud infrastructure (RF: Indeterminate)
17 Oct, ~08:15
User 30-day baseline reviewed: 201 consistent sign-ins from single London IP
17 Oct, ~08:20
Permission risk assessed: Mail.Read (full mailbox read), Offline_access (MFA-bypassing persistent token)
17 Oct, ~08:30
Application confirmed as known commercial AI product — not a malicious actor-created app
17 Oct, ~08:35
Escalation sent to client — permissions risk explained, revocation and policy change recommended
17 Oct, ~16:00
Client IT confirms: user access to app revoked, consent policy review underway
17 Oct, ~17:00
Ticket closed — access revoked, policy remediation initiated
Technical Analysis

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.

Environment
Microsoft Sentinel — Azure AD Audit Logs
Microsoft 365 / Azure AD
Recorded Future (IP enrichment)
Signals
Suspicious application consent for offline access — Azure AD Audit Logs
Permissions granted: Mail.Read, User.Read, Offline_access
Consent IP: [MSFT_INFRA_IP] — Microsoft OAuth infrastructure (login.microsoftonline.com)
Offline_access = persistent refresh token, operates outside MFA enforcement boundary
Evening consent event (20:34 UTC) — outside standard business hours
What I Checked
Consent source IP enriched via Recorded Future: clean Microsoft OAuth portal — legitimate user action confirmed
User 30-day baseline: 201 consistent sign-ins from single London IP — extremely stable pattern
Permission risk assessed independently: User.Read (low), Mail.Read (high), Offline_access (critical — MFA-bypassing persistent token)
Non-interactive sign-ins checked — assessed whether app had already initiated refresh token exchange
Application confirmed as known commercial AI product — not a malicious actor-created app
Tenant consent configuration: users can consent without admin approval (Microsoft default — systemic risk)
Tenant-wide consent audit: all offline_access grants in last 90 days reviewed
Actions Taken
Escalation sent — Mail.Read + Offline_access risk combination explained, revocation and policy change recommended
Client IT revoked user access via Azure AD Enterprise Applications admin console — refresh token invalidated
Recommended immediate restriction of user consent: require admin approval for all third-party app consents
Recommended tenant-wide audit of all enterprise application consent grants with sensitive permissions
Indicators of Compromise
TypeIndicatorNotes
ApplicationThird-party AI Application (commercial — name redacted)Legitimate app — risk is in the permissions granted, not the application itself
PermissionsMail.Read, User.Read, Offline_accessMail.Read + Offline_access = persistent MFA-bypassing mailbox access channel
Consent IP[MSFT_INFRA_IP]Clean Microsoft infrastructure — OAuth consent portal (login.microsoftonline.com)
User Baseline201 sign-ins from single consistent IPExtremely stable pattern — confirms consent event was a genuine user action
Critical RiskOffline_access refresh tokenPersists beyond session; outside MFA enforcement; survives password change in some configurations
MITRE ATT&CK Mapping
TacticTechniqueIDObserved
Initial AccessValid Accounts / Consent PhishingT1078.004 / T1566User-granted OAuth consent — legitimate user action with excessive permissions
PersistenceAccount Manipulation: Additional Cloud CredentialsT1098.001Refresh token from Offline_access = persistent credential beyond active session
CollectionEmail Collection: Remote Email CollectionT1114.002Mail.Read enables full remote mailbox content access by third-party
Defense EvasionUse Alternate Authentication MaterialT1550Refresh token operates outside MFA enforcement — cannot be blocked by MFA policy alone
Detection Logic (KQL)
// 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, TargetResources
Analyst NotesMuhammad Fezzan

This 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.

Lessons Learned
Offline_access is the highest-risk OAuth scope — escalate regardless of the application's reputation.
Legitimate applications with broad permissions represent real and ongoing risk.
Default Azure AD user consent settings are a systemic risk — restrict to require admin approval.
The tenant-wide KQL query is the most critical step — one alerted consent may mean many more silent grants.
Restricting user-level consent is the single highest-impact configuration change to close this attack surface.
Recommendations
R1Restrict user OAuth consent immediately: change Azure AD app consent policy to require admin approval for all third-party app consents. This is the single highest-impact configuration change available — it closes the entire illicit consent grant attack surface for the tenant.
R2Audit all existing consent grants: use Azure AD Enterprise Applications and Microsoft Graph API to enumerate all apps with user-level consents. Revoke any with Mail.Read, Mail.ReadWrite, Files.ReadWrite, or Offline_access unless explicitly reviewed and business-justified.
R3Enable the Azure AD Consent Phishing Detection workbook in Sentinel: provides ongoing visibility and alerting for OAuth consent events, including bulk consent grants that may indicate a consent phishing campaign.
R4User education on OAuth permissions: inform users that 'Sign in with Microsoft' on third-party apps can provide those apps with access to their corporate email and files. Users should not consent to apps requesting sensitive permissions without IT approval, regardless of how legitimate the application appears.
SIG
Case Certification
Muhammad Fezzan
SOC ANALYST
DIGITAL TIMESTAMP
OCT 2025 // REG-008-FS
← All incidentsCase anonymised