What Is MFA Fatigue?

MFA fatigue (MITRE T1621 — Multi-Factor Authentication Request Generation) is a technique where an attacker who has obtained valid credentials bombards the target’s registered MFA device with push notification requests. The goal is to provoke approval through exhaustion, confusion, or the victim assuming the notifications are a technical glitch and approving one to make them stop.

The technique doesn’t break MFA. It exploits the human element: an attacker with stolen username and password can trigger unlimited push notifications on many MFA platforms by repeatedly attempting to authenticate. Unlike TOTP codes (time-limited, require attacker to be synchronised with the victim), push notification flooding can be sustained indefinitely as long as the credentials remain valid.

Groups including Scattered Spider (UNC3944), LAPSUS$, and multiple ransomware initial access brokers have used this technique to bypass MFA in high-profile intrusions at Uber, MGM Resorts, and Caesars Entertainment.

How Attacks Play Out

The typical attack sequence:

  1. Attacker obtains username and password through phishing, credential stuffing, or purchase from an initial access broker.
  2. Attacker initiates repeated authentication attempts against the corporate SSO (Okta, Entra ID, Ping), each generating a push to the victim’s registered device.
  3. In some variants, the attacker contacts the victim directly via phone, SMS, or WhatsApp, impersonating IT support and claiming the notifications are legitimate and should be approved.
  4. Victim approves a push — either through social engineering, fatigue, or confusion.
  5. Attacker receives an authenticated session token, bypassing MFA.

Advanced variants combine push bombing with SIM swapping to take over the registered phone number entirely, or use “MFA bombing to TOTP downgrade” — flooding push notifications while simultaneously attempting to social-engineer the victim into revealing a TOTP code.

Key Log Sources

Effective detection requires MFA provider logs, not just directory sign-in logs. The critical events:

Entra ID (Azure AD):

  • SignInLogs — authentication attempts, MFA method used, MFA result
  • AADNonInteractiveUserSignInLogs — background token acquisition
  • Event code 50074 — MFA required but not satisfied
  • Event code 50076 — MFA challenge issued
  • Event code 50079 — MFA push sent
  • Event code 0 with authenticationRequirement multiFactorAuthentication — successful MFA

Okta System Log:

  • user.authentication.auth_via_mfa — MFA completion
  • user.mfa.factor.deactivate — factor removed (post-compromise cleanup)
  • policy.evaluate_sign_on with outcome DENY or CHALLENGE
  • system.push.send_factor_verify_push — push notification sent

Microsoft NPS Extension / RADIUS:

  • Repeated Access-Reject followed by a single Access-Accept within a short window

Sigma Rule: High-Frequency MFA Push Flooding

title: MFA Push Notification Flooding — Potential Fatigue Attack
id: a4c8e3f1-2b9d-4a7e-8f5c-1d6b3e2a9c7f
status: experimental
description: Detects a high volume of MFA push notifications sent to a single user in a short window, consistent with push bombing / MFA fatigue attacks.
author: SOC Analyst Hub
date: 2026-06-20
references:
  - https://attack.mitre.org/techniques/T1621/
logsource:
  product: azure
  service: auditlogs
detection:
  selection:
    EventName: "Sign-in activity"
    ResultType: "50074"          # MFA required, not satisfied
    AuthenticationRequirement: "multiFactorAuthentication"
  timeframe: 10m
  condition: selection | count() by UserPrincipalName > 10
fields:
  - UserPrincipalName
  - IPAddress
  - Location
  - UserAgent
  - ResultType
falsepositives:
  - Legitimate user with repeated auth failures during SSO troubleshooting
  - Automated scripts retrying authentication
level: high
tags:
  - attack.credential_access
  - attack.t1621

Sigma Rule: Push Approval After Sustained Failure Burst

This catches the pattern of many failures followed by a sudden success — the approval event after flooding.

title: MFA Push Approved After High-Frequency Failures
id: b7d2f4a1-9e3c-5b8f-2a1d-6c4e8f7b3d9a
status: experimental
description: Detects a successful MFA push approval that immediately follows a burst of MFA failures from the same user, indicating potential fatigue attack success.
author: SOC Analyst Hub
date: 2026-06-20
logsource:
  product: azure
  service: signinlogs
detection:
  failures:
    ResultType:
      - "50074"
      - "50076"
    AuthenticationRequirement: "multiFactorAuthentication"
  success:
    ResultType: "0"
    AuthenticationRequirement: "multiFactorAuthentication"
    AuthenticationMethod: "Push"
  timeframe_failures: 30m
  timeframe_success: 10m
  condition: >
    success AND (count(failures) by UserPrincipalName within timeframe_failures > 5)
    AND success.UserPrincipalName = failures.UserPrincipalName
falsepositives:
  - User with connectivity issues finally succeeding after retries
level: critical
tags:
  - attack.credential_access
  - attack.t1621

KQL: Entra ID Push Flooding Detection

// MFA Fatigue — High Volume Push Requests per User (10-minute window)
SignInLogs
| where TimeGenerated > ago(24h)
| where AuthenticationRequirement == "multiFactorAuthentication"
| where ResultType in ("50074", "50076", "50079")
| summarize
    PushCount = count(),
    UniqueIPs = dcount(IPAddress),
    Locations = make_set(Location),
    FirstAttempt = min(TimeGenerated),
    LastAttempt = max(TimeGenerated)
    by UserPrincipalName, bin(TimeGenerated, 10m)
| where PushCount > 8
| sort by PushCount desc
// Push Bombing Followed by Successful Auth — Likely Fatigue Attack
let failures = SignInLogs
| where TimeGenerated > ago(1h)
| where AuthenticationRequirement == "multiFactorAuthentication"
| where ResultType != "0"
| summarize FailureCount = count(), LastFailure = max(TimeGenerated) by UserPrincipalName;
let successes = SignInLogs
| where TimeGenerated > ago(1h)
| where AuthenticationRequirement == "multiFactorAuthentication"
| where ResultType == "0"
| where AuthenticationDetails contains "Push"
| project UserPrincipalName, SuccessTime = TimeGenerated, IPAddress, AppDisplayName, Location;
successes
| join kind=inner failures on UserPrincipalName
| where FailureCount > 5
| where SuccessTime > LastFailure
| project UserPrincipalName, SuccessTime, FailureCount, IPAddress, AppDisplayName, Location
| sort by FailureCount desc

Detecting Number Matching Bypass Attempts

Modern Entra ID and Okta implementations can require the user to enter a number displayed on the login screen into their authenticator app (number matching), which defeats pure push flooding. However, attackers are adapting: in social engineering variants, the attacker reads the number to the victim over the phone, claiming it’s a security verification code. Detection here moves to behaviour:

// Unusual push auth from high-risk location after business hours
SignInLogs
| where TimeGenerated > ago(7d)
| where AuthenticationRequirement == "multiFactorAuthentication"
| where ResultType == "0"
| where AuthenticationDetails contains "Push"
| where RiskState == "atRisk" or RiskLevelDuringSignIn in ("high", "medium")
| where hourofday(TimeGenerated) !between (7 .. 19)  // Outside 07:00–19:00
| project
    TimeGenerated,
    UserPrincipalName,
    IPAddress,
    Location,
    RiskLevelDuringSignIn,
    AppDisplayName,
    DeviceDetail

Okta — Detecting Push Fatigue via System Log

// Okta System Log query (Okta Log Streaming to Splunk/Sentinel)
eventType="system.push.send_factor_verify_push" 
| stats count as push_count by actor.alternateId _time span=10m 
| where push_count > 8

Hardening Controls

Enable number matching: Entra ID and Okta both support requiring the user to type a displayed number into the authenticator app. This single control eliminates pure push flooding without phone contact.

Enable additional context in push notifications: Show the requesting application and location in the push notification. Users are far more likely to spot a suspicious push if they can see it’s claiming to come from “Salesforce” while they’re sitting at their desk.

Enforce MFA session policies: Configure Conditional Access to block sign-ins from high-risk locations or unfamiliar devices regardless of MFA result. A successful push from a Tor exit node or a flagged datacenter IP should still be blocked.

Implement temporary access passes: For users who report push flooding in real time, disable their phone factor and issue a Temporary Access Pass for re-enrollment — this prevents further flooding and provides a tracked re-enrollment path.

Alert on factor deactivation: Attackers frequently deactivate MFA methods post-compromise to prevent lockout. Any factor deactivation not initiated through self-service and not correlated with a helpdesk ticket should trigger immediate investigation.