Your MFA worked perfectly. The attacker was already inside the session.
Adversary in the middle phishing does not steal your password. It stands between you and the real login page, lets you authenticate correctly, and walks off with the session cookie that authentication produced. One kit alone is reported to have taken more than 96,000 victims. This is a lesson about why the strongest login in the world protects nothing after the first second, and what a control has to look like if it wants to survive.
It is a Tuesday afternoon in accounts payable. Priya has forty minutes before a status call and one supplier thread to close out. The last message has an attachment notification: a revised invoice, shared through the supplier's document portal. The thread is real, she has been replying into it for three weeks, and the sender's name is spelled correctly, because it is the supplier's actual mailbox, which somebody else logged into eleven days ago.
She clicks. A Microsoft sign in page loads. Not an imitation of one. It has the right fonts, the right spacing, the tenant's own background image that her IT team uploaded in 2023, and her email address already filled in. She types her password. The page thinks for a moment and then shows the authenticator prompt she has seen four hundred times. Her phone buzzes. She reads the two digit number on the screen, taps the matching number in the app, and confirms with her fingerprint. The page accepts, she lands on a real if slightly stale invoice, and she closes the tab.
Priya did everything right. Strong unique password from the company vault. Multi factor authentication on. Number matching, which exists specifically to defeat prompt bombing. A biometric confirmation. Not one of those controls failed. Every single one performed exactly as designed.
And ninety seconds later, in a different country, somebody opened her mailbox without a password, without an MFA prompt, and without triggering a single sign in alert. They read six weeks of her mail, created an inbox rule filing anything containing "invoice" or "wire" into an obscure archive folder, and found the supplier onboarding thread. On Thursday a payment run went to an account number that had been quietly changed on Wednesday.
Short answer: Adversary in the middle phishing does not capture your password to replay it later. It proxies the real login page, lets you complete multi factor authentication against the genuine identity provider, and steals the session cookie that authentication issues. That cookie is a bearer token: whoever holds it is you, for its lifetime, with no further authentication. This is why phishing resistant MFA hardens the login and still leaves every action taken afterward unprotected.
What actually happens in an adversary in the middle attack?
Most people carry a mental model of phishing that was accurate in about 2014. In that model, a fake page collects your password, stores it in a database, and someone logs in with it later. In that model, multi factor authentication is a complete answer, because the stolen password is only one factor and the attacker cannot produce the second.
Adversary in the middle, usually written AiTM, breaks that model completely. Here is the mechanism, slowly.
Step one: the proxy, not the copy
The attacker does not build a copy of the Microsoft login page. Building copies is tedious, they drift out of date, and they cannot handle the branding that every tenant customises. Instead the attacker stands up a reverse proxy. When Priya's browser asks the attacker's server for the login page, the attacker's server turns around, requests the genuine page from Microsoft, and passes it back to her, changing only what it needs to.
This is why the page looked perfect. It was perfect: Microsoft's own page, fetched live, with her tenant's own background image, because the proxy asked for it in real time and Microsoft answered. There is no visual tell, because there is nothing visually different. The only artefact is the domain in the address bar, which is the one thing a person under mild time pressure reliably does not read.
Step two: the relay
Priya types her password. It goes to the proxy, which immediately submits it to the real Microsoft endpoint. Microsoft decides it is correct and that a second factor is required, and that challenge comes back through the proxy to her screen. The attacker is not guessing at the authentication flow. The attacker is a courier, faithfully carrying messages both ways. Whatever Microsoft asks, Priya sees; whatever Priya answers, Microsoft receives. The conversation is genuine at both ends, and the attacker is in the middle holding the envelope.
Step three: the second factor does its job
Her phone buzzes because Microsoft genuinely wanted a second factor. Number matching shows two digits on the login screen and asks her to select them in the app, defeating the older attack where someone spams push notifications until a tired user taps approve. It is a good control and it works against the attack it was built for.
It does nothing here, because Priya is not being tricked into approving somebody else's login. She is approving her own. The numbers match because it is genuinely her session being authenticated, and her fingerprint confirms a real intent to sign in. Everything she is asked to verify is true.
Step four: the harvest
Microsoft, satisfied, issues a session, which in a browser is a cookie or a small set of them. The proxy receives it, because as far as Microsoft is concerned the proxy is the browser that just authenticated. It passes a working session back to Priya so her experience is normal, and keeps a copy.
The attacker imports that cookie into their own browser. Outlook loads, the cookie is presented, and Microsoft concludes this is an already authenticated session belonging to Priya. No password prompt. No MFA prompt. No sign in event of the kind that triggers most alerting, because from the identity provider's view no new sign in occurred. It already happened, ninety seconds ago, and it was legitimate.
Why does a stolen session cookie beat multi factor authentication?
Here is the analogy that makes it click, and then the precise version underneath it.
Think about a hotel. At the front desk you present a passport, a credit card, and a booking reference, and the clerk studies all three. It is a genuinely strong identity check. Satisfied, they hand you a key card.
From that moment nobody checks your passport again. The card opens your room, the gym, the club floor, the garage. Drop it in the lobby and the door does not ask the stranger who picks it up for a passport. The door asks for a card, and it has one. The front desk check was strong; the key card is a bearer token, and strength at the desk does not transfer to the door, because the door is not verifying identity. It is validating a token, and tokens do not care who holds them.
Now the precise version. Web sessions are bearer credentials by design. HTTP is stateless, so after you authenticate the server issues a token meaning "the holder has already proved they are user X". Every later request presents the token instead of repeating the authentication, because repeating it on every request would be unusable. That decision is correct and it is not going away.
The consequence is structural. Authentication happens once. Authorization for everything afterwards is inherited from that moment. Call it Session Inherited Authorization, and once you have the name you will see it everywhere. It is not a bug in Microsoft's implementation or Okta's. It is the shape of the web, and it produces an uncomfortable sentence worth sitting with: the strength of your login has almost no relationship to the safety of the actions taken after it. You can put a hardware key on the front door. The attacker is attacking the key card.
How big is this problem, in numbers?
Big enough that it is now the default, not the exotic case.
The clearest single data point is Tycoon 2FA, a phishing as a service platform that Microsoft tracks under the actor name Storm-1747. It has been in operation since around August 2023, selling AiTM capability as a subscription so that attackers with no technical skill can run these campaigns. Microsoft, Europol and a coalition of industry partners disrupted it in an operation reported in March 2026, seizing around 330 domains. The victim count attributed to the platform in that reporting is more than 96,000 people, and the platform was associated with tens of millions of phishing messages per month (Microsoft Threat Intelligence, March 2026; Europol; Proofpoint).
Tycoon was not alone, and that is the more important number. Sekoia's threat detection and research team identified eleven distinct adversary in the middle phishing kits in active commercial operation between January and April 2025, with Tycoon 2FA leading on prevalence (Sekoia, 2025). Eleven competing products in a four month window is not a novel technique. It is a mature industry with vendors.
Takedowns move that market rather than ending it. Barracuda's threat research in April 2026 reported that after the disruption the Tycoon model did not die but scattered across smaller operators. That is the normal outcome for phishing as a service enforcement, and it is why a defence that depends on any particular kit being offline is a poor plan.
The downstream cost lands where the money is. Business email compromise, which is what a stolen mailbox is usually monetised into, produced 3.05 billion dollars in reported United States losses across 24,768 complaints in 2025, with 86 percent of it leaving by wire or ACH, at an average of roughly 123,000 dollars per complaint (FBI IC3 2025 Internet Crime Report). A single stolen session in the wrong mailbox is a six figure event.
What can an attacker actually do with a stolen session?
Ask this inside your own organisation, because the answer is almost always worse than people assume. The instinct is "they can read email". The reality is that a modern identity provider federates dozens of applications, and a session at the identity provider is frequently a session everywhere. Here is the blast radius, roughly ordered by how quietly each action can be performed.
| Action in a stolen session | Does it need re-authentication? | Why it matters |
|---|---|---|
| Read the entire mailbox and calendar | No | Supplies the vocabulary, the relationships, and the timing for the fraud that follows |
| Create an inbox or forwarding rule | Usually no | Hides the victim's own alerts from them, and persists after the session dies |
| Send mail as the user, inside a real thread | No | This is what makes the next victim click, and why AiTM spreads laterally between organisations |
| Approve a workflow request in chat or email | No | Approvals delivered as a reply or a reaction inherit the session, not the human |
| Change a payee or bank detail in a connected app | Usually no | The actual monetisation step in most BEC losses |
| Pivot into federated SaaS applications | Frequently no | Single sign on was the point, and it works for whoever holds the session |
Read that middle column again. The honest summary of most enterprise SaaS is that authentication is required to start a session and almost nothing is required afterwards. We spent a decade hardening the front door and left every interior door on the latch.
Run that column against your own stack and write the answer down. Most teams find it is "no" for every row, which is not a misconfiguration but the platforms' default. It does mean the whole control story for those actions rests on the session never being stolen, which brings us to the second delivery mechanism.
The variant with no phishing page at all
AiTM is the loud version. There is a quieter one that skips the lure entirely.
Infostealer malware harvests credentials and, importantly, session cookies straight from the browsers on an infected machine. The victim never sees a phishing page because there is not one. The machine is simply infected, often through a cracked application or a malicious download, and the browser's credential and cookie stores are copied out and sold in bulk on criminal markets.
The clearest large scale illustration is the campaign against Snowflake customers, tracked as UNC5537. The attackers did not breach Snowflake's platform. They used credentials harvested by infostealers, in many cases from contractor and third party machines rather than the victim organisations' own laptops, to reach customer tenants that were not protected by multi factor authentication. Public reporting puts the campaign at at least 165 organisations, with records belonging to at least 100 million people exposed across victims including Ticketmaster, AT&T, Santander and Advance Auto Parts.
Two lessons compound. The credential does not have to be phished from your user; it can be stolen from a contractor's personal machine three companies away. And once you accept that sessions will leak by routes you do not control, defending only the login becomes a strategy that depends on a promise nobody can keep.
Why do number matching, conditional access, and token binding not fix this?
They are all good. Deploy all of them. None of them changes the structure, and it is worth being precise about why, because "we already have conditional access" is the sentence that ends most of these conversations prematurely.
| Control | What it genuinely does | What it leaves untouched |
|---|---|---|
| Number matching | Defeats push bombing, where a user taps approve on a prompt they did not initiate | The user in an AiTM flow did initiate it. The prompt is legitimate. Matching succeeds. |
| FIDO2 security keys and passkeys | Defeats credential relay at login, because the assertion is bound to the true origin and will not sign for a proxy domain | The login. Once a session exists, the key is not consulted again for anything. |
| Conditional access with device compliance | Blocks many replays from unmanaged devices, raising cost meaningfully | Attackers moving to compliant or residential infrastructure, and every action inside a compliant session. |
| Short token lifetimes | Shrinks the window | The window is measured in minutes to hours. Creating a forwarding rule takes eight seconds. |
| Token binding (RFC 8471) and DPoP (RFC 9449) | Cryptographically ties a token to a client key, so a lifted token fails elsewhere. Genuinely the right idea. | Deployment. Token binding never reached broad browser support, and DPoP adoption is uneven. Both bind the session to a device, not the action to a human. |
| Session anomaly detection | Sometimes catches impossible travel or odd behaviour after the fact | It produces a probability, after the action. The forwarding rule already exists. |
Look down the third column. Every one of these controls either strengthens the moment of login or estimates whether a session is suspicious. Not one changes what a valid session is permitted to do. The interesting row is token binding, the closest thing the standards world has to a structural answer, and its story is instructive: specified, sound, and stalled on deployment for most of a decade.
What would actually stop the loss?
Separate the two questions the system is currently answering with one artefact.
A session cookie answers: has this browser authenticated recently? It answers that well. What a payment release endpoint needs to know is different: did the specific human allowed to authorise this action intend this exact action, just now? A cookie cannot answer that and was never designed to. Asking it to is the category error at the heart of the problem.
So make consequential actions carry their own proof. The session still authenticates the request. A fresh signature from the user's enrolled device, over the exact payload, authorises it. Two artefacts, two jobs, and the second does not inherit from the first.
Here is the difference, concretely.
// What the session presents today.
// Meaning: "some browser authenticated as [email protected] at 14:02."
// Anyone holding this string is priya, for its lifetime.
Cookie: ESTSAUTH=0.AXoA...9Kw; Path=/; HttpOnly; Secure
// What an action-bound proof presents instead.
// Meaning: "priya's enrolled device signed THESE EXACT BYTES at 14:47."
// Holding it proves one action, once. It cannot be replayed
// against a different payee, a different amount, or a different day.
{
"action": "vendor.bank_details.update",
"payload": {
"vendor_id": "V-40881",
"account_new": "GB29NWBK60161331926819",
"account_old_sha256": "9f2c...a10b",
"effective": "2026-09-04"
},
"payload_sha256": "b41d8f...c7e2",
"signed_at": "2026-09-03T14:47:09Z",
"signer_key": "did:key:z6Mkf...T1a",
"signature": "3045022100b8...ec"
}
Three properties matter. The signature covers the hash of the payload, so it is not a general approval of "something Priya wanted to do", it is arithmetically welded to this vendor, this account number, this date. Change one character of the destination and it no longer verifies. There is nothing to replay and nothing to redirect.
Second, the signing key lives in the secure element of her enrolled device and is exercised with a biometric. The attacker holding her cookie has her mailbox, her calendar, her SaaS applications and her identity for every read on the system. They do not have her phone. They can see that a payee change is possible and they cannot make one.
Third, the result is a receipt that verifies offline against a published key, so an auditor, a bank or an insurer can confirm that a specific human authorised a specific payload without calling any vendor's API, including ours. That is the difference between a log line, which asserts something happened, and a receipt, which proves it.
A worked example: the payee change that did not happen
Return to Priya's Thursday, with an action bound control in place on exactly one endpoint.
The attacker, in her session, opens vendor record V-40881 and edits the bank details. Everything up to here is identical: they read the record, see the current account, type a new one. The interface does not stop them, because stopping them at the interface is a losing game.
When they submit, the application computes the canonical payload above, hashes it, and returns a pending state. The change is not saved. A signing request appears in Priya's authorisation inbox and her enrolled phone lights up. The prompt does not say "approve a change". It says:
Vendor V-40881, Meridian Components Ltd
Bank account change
From ****6819 (on file since 2023-04-11)
To GB29NWBK60161331926819
Effective 4 September 2026
Requested from a session in Frankfurt, 14:47.
Sign to apply. Decline to block and alert security.
There are three outcomes and all three are good. Priya is at her desk, did not request this, and declines: the change never applies and the security team gets something rare, a confirmed malicious action attempt with a timestamp, an origin, and a named human who explicitly rejected it. Or she is in a meeting and ignores it, the request expires, and the attacker's window closes with no action from anyone. Or, the case people forget, she genuinely did request the change, taps her fingerprint, and it saves in four seconds with a receipt attached to the vendor record. Six months later an auditor asks who approved that bank change, and the answer is not a username in a log, which is the system asserting something about itself. It is a signature that verifies independently.
Notice what we never had to do. We never decided whether the session was suspicious, never spotted the phishing page, never won a detection race against a kit that updates weekly. We moved the decision to a place the attacker cannot reach, and the question of how convincing the attack was stopped mattering.
Which actions deserve this, and which do not?
Gating everything would be unusable and unnecessary, and any vendor who tells you otherwise is selling friction. Pick a small set of action classes where the cost of being wrong is high and the frequency is low. Those two properties almost always travel together. A workable starting taxonomy, in rough priority order:
- Money movement. Payment release above a threshold, and every payee or bank detail change regardless of amount. The change is the attack; the payment is just the consequence.
- Account shape changes. Adding an authenticator, changing a recovery address or phone number, adding a delegate. These convert a borrowed session into permanent ownership. See the help desk reset problem for the same failure arriving by a different door.
- Privilege grants and data egress. Admin role assignment, service account creation, API key issuance, full table exports, and forwarding rules, which are how attackers hide the rest of their work from the person best placed to notice it.
- Anything an autonomous agent initiates with a side effect. Agents holding sessions widen this problem considerably, which is the subject of proving an agent is authorised.
In a typical mid sized organisation that is a few dozen signatures per person per year: roughly one four second interruption a fortnight, in exchange for removing a category of loss.
What this does not fix
Every honest control has a boundary, and these are worth stating plainly.
A fully compromised endpoint is still a fully compromised endpoint. Malware owning the machine at kernel level can misrepresent what is displayed. The companion device model reduces this considerably, because the phone renders the payload independently of the desktop, but two independently compromised devices belonging to the same person defeat it. That is a real limit, and it is why this complements endpoint security rather than replacing it.
It does not stop a human who signs willingly. Someone socially engineered into genuinely believing a payee change is correct will sign it, and the signature is valid because it accurately records what happened. What you gain is unambiguous evidence, plus a moment of deliberate friction on the exact screen where the destination account is shown in full, which is more than most fraud ever gets.
Enrolment is the trust bottleneck. Somebody, once, binds the right keypair to the right human. Do that badly and everything downstream inherits the mistake. Enrol during a moment you already treat as high assurance, and enrol two authenticators per person so "my phone broke" never becomes "so we turned the control off".
It does not cover reads. An attacker in a stolen session can still read the mailbox, and that confidentiality damage is real. Action binding addresses the actions that move money and grant power; monitoring and rapid session revocation remain necessary for the rest. Service accounts need a different pattern again: a nightly batch job has no human to sign, so those flows want scoped, time bound, revocable delegation issued once and constrained tightly.
What to do this week
Concrete, in order, none of it requiring a budget cycle.
- Run the twenty minute exercise. List your five most consequential SaaS actions and confirm, by testing, whether any of them requires anything beyond a live session. Write the answer down. It is the most persuasive document you will produce this quarter.
- Alert on the persistence steps, not the login. Inbox rule creation, forwarding rule creation, and new authenticator enrolment are the highest signal events in the whole chain, and they are cheap to alert on today.
- Pick one endpoint and bind it. One. Payee change is the usual best first choice: low volume, high consequence, unambiguous payload. Ship it, measure the friction honestly, then expand.
- Deploy phishing resistant MFA anyway. None of this argues against passkeys or security keys. They make the first step expensive. Just stop describing them as protection for what happens afterwards, because that sentence is doing real damage in board decks.
If you want to see the shape of it working, the privileged action demo gates an admin grant on a device signature, and the integration docs show the single call that turns an endpoint from session authorised into action authorised.
Eleven kits in four months is what a discovered arbitrage looks like. The kits will keep improving and the takedowns will keep scattering them, so the detection race stays a race, which is a thing you can lead and never win. The alternative is not a better detector. It is a different question at the moment of consequence: not "does this session look legitimate", which is a probability, but "did this human sign this exact thing", which is a fact.
Frequently asked questions
Does phishing resistant MFA stop adversary in the middle attacks? It stops the credential relay at login, because a passkey or FIDO2 assertion is bound to the true origin and will not sign for a proxy domain. That is real and worth deploying. It does not protect actions taken after the session exists, which is where the money is lost. Phishing resistance is a property of your login, not of your approvals.
What is Tycoon 2FA? A phishing as a service platform, tracked by Microsoft as Storm-1747 and active since around August 2023, that sold adversary in the middle capability by subscription. It proxied real Microsoft 365 and Google Workspace login pages, relayed multi factor prompts, and captured session cookies. A March 2026 disruption involving Microsoft, Europol and industry partners seized roughly 330 domains and was associated with more than 96,000 victims.
How does session cookie theft bypass MFA? The cookie is issued after multi factor authentication succeeds, so it represents an already authenticated state. Presenting it does not trigger a new authentication, because from the server's perspective no new sign in is occurring. Whoever holds the cookie is treated as the user for its lifetime, which is why bearer tokens are the real target rather than passwords.
What is token binding and does it fix this? Token binding, specified in RFC 8471, cryptographically ties a session token to a key held by the client, so a token lifted to another machine fails. It is the right structural idea and it never achieved broad browser deployment. DPoP (RFC 9449) pursues a similar goal for OAuth with better momentum. Both bind a session to a device; neither binds an action to a human.
Do we have to gate every action with a signature? No, and you should not try. Pick a small set of action classes where consequence is high and frequency is low: payment release, payee and bank detail changes, authenticator enrolment, privilege grants, bulk export and mail flow rules. For most people that is a handful of signatures a month, not a friction problem.
Sources
- Microsoft Threat Intelligence, Inside Tycoon2FA: how a leading AiTM phishing kit operated at scale, March 2026. Victim counts, domain seizures, and the Storm-1747 attribution.
- Sekoia Threat Detection and Research, adversary in the middle phishing kit census, January to April 2025. Eleven commercial kits in active operation.
- Barracuda threat research, Tycoon 2FA post disruption analysis, April 2026. Fragmentation of the model after takedown.
- Federal Bureau of Investigation, Internet Crime Complaint Center 2025 Internet Crime Report. Business email compromise totals, complaint counts, and the wire and ACH share.
- Mandiant and industry reporting on UNC5537 and the Snowflake customer credential campaign, 2024 onward. Organisation counts and infostealer sourced credentials.
- Internet Engineering Task Force, RFC 8471, The Token Binding Protocol Version 1.0, and RFC 9449, OAuth 2.0 Demonstrating Proof of Possession.
Your login answers who started the session. Only a signature answers who performed the act, and the attacker is never in the room for the first question.