Manav.id
Security ยท 16 min read

Approve is a button, not a sentence.

The industry mostly fixed push bombing, and number matching deserves the credit. What it did not fix is the reason the attack worked in the first place, which is that an approval prompt has never been required to say what it is approving.

It is twenty to three in the morning and a phone is buzzing on a bedside table.

The first notification woke its owner about four minutes ago. They squinted at it, saw the familiar icon of the company authenticator, did not recognise the request, and dismissed it. The second one arrived a minute later. The third came while they were still holding the phone. By the sixth, they are properly awake and mildly angry, and the thought forming is not "I am under attack", it is "this thing is broken again".

That thought is the entire attack. It is not stupidity and it is not carelessness. It is a completely reasonable inference from experience, because the overwhelming majority of unexpected authentication prompts that a normal employee has received in their working life have been glitches, stale sessions, a background application reconnecting, or the mail client on a tablet they forgot they owned. The prior probability that an unexplained prompt is malicious is, from the user's vantage point, low. Attackers are not exploiting a character flaw. They are exploiting an accurate base rate.

Then the phone rings. The caller is calm, slightly bored, and says they are from the service desk running an overnight migration, that a few accounts are throwing repeated prompts, apologies for the hour, and could you just approve the next one so they can close the ticket. Everything about the call matches the reality the person is currently experiencing. And there is a very human pull toward the explanation that makes the buzzing stop.

Most organisations have now made this specific script much harder, and that is a genuine achievement worth stating before anything else.

Short answer: Number matching largely defeats classic MFA fatigue, because approving now requires reading a digit shown on the login screen rather than tapping a button. It does not fix the underlying flaw. A push approval still authorises an operation the prompt does not describe, so for consequential actions the approval should be a signature over the specific operation, rendered on the enrolled device before the user consents.

What is an MFA fatigue attack?

The preconditions are unglamorous. The attacker already has a valid username and password, obtained from a credential dump, a reused password, an infostealer log, or a phishing page. The password is not the obstacle. The second factor is.

With a classic push based second factor, the attacker submits the stolen credentials over and over. Each submission causes the legitimate user's authenticator application to display a prompt asking them to approve a sign in. The attacker's hope is straightforward: that somewhere in twenty or fifty or two hundred prompts, the user taps approve, whether out of confusion, irritation, a desire to sleep, or a belief that approving is the way to make a malfunction stop.

The technique is sometimes called push bombing or prompt bombing, and it has appeared repeatedly in advisories from the United States Cybersecurity and Infrastructure Security Agency describing the tradecraft of intrusion groups that specialise in social engineering, alongside help desk manipulation and SIM swapping. It became prominent because it required almost no technical skill, cost nothing per attempt, and worked often enough to be worth the effort.

The vishing variant, the phone call, is the version that made it reliable rather than merely cheap. A flood of prompts on its own produces a suspicious user. A flood of prompts plus a plausible explanation produces a cooperative one.

Did number matching fix it?

Largely, for this attack, yes. This needs to be said clearly and early, because a great deal of security content still describes push bombing as though nothing has changed since 2022, and a reader following that advice would be preparing for a fight that has substantially moved.

Number matching changes the approval from a binary tap into a small transcription task. The login screen displays a two digit number. The authenticator prompt asks the user to type that number rather than press a button. If the user is not looking at the login screen, they do not have the number, and the approval cannot be completed by reflex.

Microsoft moved Microsoft Authenticator tenants to number matching by default in 2023, and other major push providers offer equivalent mechanisms. The effect on the naive attack is direct and structural rather than probabilistic: a sleeping person cannot supply a digit they have never seen, no matter how many prompts arrive. The flood without a channel back to the attacker simply stops working.

What number matching actually proves

It is worth being precise about the guarantee, because the precision is where the remaining problem lives.

Number matching proves that the person approving had sight of the screen where the authentication was initiated. That is a real and useful property. It defeats the blind flood entirely, and it forces the attacker into a channel where they must speak to the victim and read them a number, which is a much narrower, noisier, more detectable operation than sending prompts in bulk.

Now notice what the guarantee does not include. It says nothing about what is being authorised. The digit proves the user saw a login screen. It does not tell them whose login screen, in which country, requesting access to which system, on behalf of which application, to perform which operation. The transcription task confirms a shared view of a number. It does not confirm a shared understanding of an act.

So the attacker who can get a person on the phone can still read them a two digit number, and the person still has no more information about what they are approving than they had before. The barrier went up. The thing behind the barrier did not change.

What is actually wrong with the approval?

Here is the design flaw, stated as plainly as possible: the approval carries no content.

Consider what a push prompt typically says. "Approve sign in?" Perhaps with an application name, a city derived from an address lookup that is frequently wrong, and a timestamp. The user is being asked to make a security decision, and the total information supplied to make it is a verb, a noun, and a location guess.

Compare that with what a signature means in every other context humans have used one. Signing a cheque commits you to a number and a recipient printed above the line. Signing a contract commits you to terms you can read. In each case the signature is meaningless without the document, and its whole function is to attach a person to a specific statement.

An approval tap is a signature with no document. It attaches a person to an event, and the event is defined entirely by whoever triggered it. The user contributes consent and receives no description of what they are consenting to. That is not a user education problem, and it cannot be repaired by training, because there is nothing for a well trained user to inspect.

Habituation is not a personal failing

There is a well established observation in human factors work, familiar to anyone who has designed alarms or warnings, that repeated exposure to a signal that is almost always benign reliably degrades the response to it. This is not a controversial finding and it is not specific to computers. It is why hospital staff tune out infusion pump alerts, why drivers stop noticing a dashboard light that has been on for a month, and why a car alarm in a city street produces no reaction from anybody.

Push approvals are engineered to produce exactly this. A typical knowledge worker approves several prompts a day, effectively all of them legitimate, effectively all of them looking identical. The system is training a reflex, deliberately and continuously, and then relying on that reflex being suspended at the one moment it matters. That is an unreasonable thing to ask of a person, and it is a strange thing to build on purpose.

The productive response is not more training. It is to make the rare consequential approval look and behave differently from the routine one, and to give it content a person can actually evaluate.

Where else does this pattern appear?

Once you see the empty approval, it becomes visible in several places that look unrelated.

The clearest parallel is device code phishing, where a user is persuaded to enter a code on a completely genuine provider page. There is no fake website, no lookalike domain, and nothing for a link scanner to catch. The user is authenticating correctly, on the real service, and authorising something they cannot see, because the screen shows an application name that the attacker chose. We covered the mechanics in the piece on device code phishing, and it is worth reading alongside this one, because the two attacks share a single root: consent collected in a context that displays almost nothing about what is being consented to.

The same shape appears in blind signing, where a user approves a transaction whose true contents differ from what their screen displays. It appears in consent screens that list scopes in language nobody parses. And it is now being copied, at speed, into artificial intelligence tooling, where "approve this action" buttons are appearing in agent interfaces with roughly the same information density as a 2015 push prompt. We wrote about that inheritance in the piece on approval theater, and it is the reason this topic is not a historical footnote: a design flaw the industry spent four years partially mitigating is being reintroduced from scratch in a new product category.

Is prompt design a security control?

It is, and almost nobody treats it as one. Prompt wording usually belongs to whoever built the feature, gets reviewed for tone rather than for threat, and is rarely revisited.

Yet the difference between prompts is the difference between different security properties. Consider these four, which describe the same underlying event.

Prompt designWhat the user can evaluateAttacks it resists
"Approve sign in?" with accept and denyNothing beyond the fact that a prompt existsAlmost none. Defeated by a flood or a single well timed prompt.
Adds application name, approximate location, timeWeak contextual mismatch, if the user knows what normal looks likeCareless attackers. The context is advisory and often inaccurate.
Number matching, user types a digit from the login screenThat they are looking at the initiating screenBlind floods, sleeping user attacks. Not a caller reading the digit aloud.
Content bound signature over a rendered payloadThe exact operation, in words, before consentingFloods, relays, pretext calls, and substituted operations. The approval is only valid for what was displayed.

Reading down the middle column is the useful exercise. Each row gives the human slightly more to work with, and only the last row gives them the thing they are actually being asked about.

What does a content bound approval look like?

The mechanism is not complicated. Instead of asking the device to approve an event, you ask it to sign a statement, and you show the human the statement first.

The server assembles the operation, serialises it deterministically, hashes it, and uses that hash as the challenge. The enrolled device renders the fields in plain language, collects a biometric or passcode confirmation, and returns an assertion over that exact hash.

payload = {
  "action":    "role.grant",
  "principal": "[email protected]",
  "role":      "aws.production.admin",
  "duration":  "PT4H",
  "requested_by": "svc-onboarding",
  "origin":    "10.14.9.31 / Frankfurt",
  "at":        "2026-09-23T02:41:07Z"
}

challenge = SHA256(canonical_json(payload))
assertion = authenticator.sign(challenge, userVerification: "required")

What the human sees on the phone, before any prompt to confirm, is not "Approve sign in?" but something closer to: Grant j.okafor production admin on AWS for 4 hours, requested by the onboarding service from Frankfurt. A person woken at two in the morning can evaluate that sentence. They may not know whether it is legitimate, but they can tell instantly whether it resembles anything they were expecting, which is a decision they were previously not equipped to make at all.

Verification is the mirror image, and the important property is that it is checkable later by someone who was not there:

ok = verify(assertion.signature,
            over: SHA256(canonical_json(payload)),
            with: enrolled_public_key(assertion.key_id))

# the receipt is the audit artifact
receipt = { payload, assertion, key_id, verified_at }

If an attacker substitutes a different operation, the hash changes, and the signature that the user produced does not verify against it. The approval cannot be lifted off one action and reapplied to another, which is precisely what an empty approval permits.

There is a working demonstration of this flow at the signing lab, and the integration details are in the developer documentation.

Honest limits

This control is narrower than it may sound, and the limits matter.

What to do this week

The first four items cost nothing and require no purchase, which is the honest place to start.

  1. Confirm number matching is on and enforced across every authenticator in the estate, including any legacy tenant or contractor group that was excluded during rollout. Exclusions are where this bites.
  2. Read your own prompts. Collect the exact text of every approval prompt your systems generate. Most teams have never seen them written down together, and the exercise usually finds two or three that say almost nothing.
  3. Rate limit and alert on prompt floods. Repeated denied prompts for one account inside a short window is a high quality signal and it is cheap to act on. Lock the account rather than continuing to ask.
  4. Tell staff the true rule, not a vague one. "Never approve a prompt you did not personally initiate, and the service desk will never ask you to approve one" is specific, memorable, and removes the ambiguity the pretext call depends on. Then make sure the service desk actually honours it, because a policy your own staff violate is training in the wrong direction.
  5. List your step up approvals. Every place where a push is used for something other than login: privilege elevation, payment release, configuration change, data export. These are where content binding is worth the friction.
  6. Bind the top of that list. Start with operations that are irreversible or high value, not with the ones that happen most. Volume is the wrong ranking criterion here.
  7. Audit any agent tooling for approve buttons. If an internal AI tool has shipped an "approve this action" control in the last year, check whether the approval is bound to the action or is simply a button in a web page the agent can reach.

Frequently asked questions

What is an MFA fatigue attack? An attacker who already holds a valid password repeatedly triggers authentication prompts on the legitimate user's device, hoping that one gets approved out of confusion, irritation or a desire to stop the interruption. It is often paired with a phone call impersonating the service desk, which supplies a plausible explanation for the flood and asks the user to approve the next prompt.

Does number matching stop MFA fatigue? It stops the blind version, and that is a substantial win. Requiring the user to type a digit shown on the login screen means someone who is not looking at that screen cannot approve at all. It does not stop an attacker who reaches the victim by phone and reads the digit aloud, because the user still has no information about what they are approving.

Why do users approve prompts they did not initiate? Because almost every unexpected prompt they have ever received was a glitch rather than an attack, so the reasonable inference is malfunction. Repeated exposure to a signal that is nearly always benign degrades the response to it, which is a well established human factors effect rather than a personal failing. The system trains the reflex it then depends on the user suspending.

Do passkeys make this irrelevant? For login, largely yes, and organisations should be moving there. The pattern survives in step up approvals for transactions, privilege grants and administrative actions, where a push prompt is still commonly used and still describes almost nothing about the operation being authorised.

What should a high risk approval prompt contain? The operation in plain language, the specific resource or amount, who or what requested it, where the request originated, and the duration or scope if applicable. Critically, the approval should be cryptographically bound to that content, so an approval given for one operation cannot be applied to a different one.

Is this the same problem as device code phishing? They share a root cause. In both cases the user authenticates correctly and consents to something the interface does not adequately describe. Device code phishing is more elegant because it uses a genuine provider page, but the underlying flaw is identical: consent collected without content.

Sources

  1. Cybersecurity and Infrastructure Security Agency, advisories describing push bombing and multifactor authentication fatigue among social engineering tradecraft: cisa.gov/news-events/cybersecurity-advisories
  2. Microsoft Security, guidance and announcements on number matching in Microsoft Authenticator and its default enablement: microsoft.com/security/blog
  3. National Institute of Standards and Technology, Special Publication 800-63B, Digital Identity Guidelines, on out of band authenticators and verifier impersonation resistance: pages.nist.gov/800-63-3/sp800-63b.html
  4. World Wide Web Consortium, Web Authentication Level 2, for assertion structure, challenge construction and user verification: w3.org/TR/webauthn-2
  5. FIDO Alliance, specifications and guidance on phishing resistant authentication: fidoalliance.org

A note on two frequently cited incidents. Push fatigue is widely reported to have featured in prominent intrusions during 2022, and those accounts are repeated in a great deal of secondary coverage. We have not attributed specific mechanics to named companies here, because the detailed public record is thinner than the retellings suggest. The technique's presence in agency advisories is sufficient to establish that it works, and the argument in this post does not depend on any single case.

A signature with no document attached is not a signature. It is a reflex the system trained and then trusted.