THIS EXPLANATION
THE ROOM
CDA·265 Computing, Data & AI 7 MIN · 8 STATIONS

Why a code sent to your phone does not stop phishing

A Socratic walk-through of why a code sent to your phone does not stop phishing — reasoned out one step at a time, not lectured.

abcdefgh
a

The question we started with

THE QUESTION #

Why does a second factor still let an attacker who built a convincing fake page straight in?

Two-factor authentication is sold as the answer to phishing. The story is intuitive: even if someone tricks you out of your password, they still lack the code on your phone, so they are stuck.

Except that organizations with mandatory two-factor authentication get phished anyway, and not by exotic means. Something in the intuitive story is wrong. Worth locating exactly where, because the fix that follows is quite different from "train users to spot fake pages".

b

Reasoning it through

REASONING #

Ask what a one-time code actually is. It is a short-lived secret that both your phone and the server can compute, or that the server sent you. Possession of the phone is what produces it. Fine. Now ask the sharper question: once produced, what stops it being used by someone other than you?

Nothing. It is a bearer token — whoever presents it, within its window, is treated as the holder. And the transport from your phone to the server is you: you read it and type it in. Which means the code inherits, exactly, whatever judgement you exercised about where you were typing.

Now build the attack from that observation. The attacker's page is not a static copy; it is a proxy sitting between you and the real site. You type your password, and the proxy immediately submits it to the genuine site. The genuine site sends you a code — a real one, from the real site, arriving on your real phone. You type it into the fake page. The proxy relays it within seconds. The real site sees a correct password and a correct, unexpired code, and does the only thing it can: it issues a session.

Notice what the attacker collects. Not just the credentials — the session cookie. From then on nothing is re-checked, because the code's job was finished at the door. The second factor did not fail; it worked perfectly, on behalf of someone else.

So what did the second factor actually buy? A change in the attacker's timing constraint, not in the kind of attack. Password-only theft can be exploited at leisure, months later, in bulk. A relayed code must be used inside its window, which forces the attacker to be online while you are being deceived. That is a real cost, and it is why the measure is worth having — but it is a cost, not a wall, and tooling has made it a cheap one.

Push approvals are the same shape with an extra weakness. If the proxy triggers the genuine prompt, you receive a genuine notification for a login you genuinely just initiated, and approving it is the reasonable thing to do. Number matching helps against the separate problem of prompt-bombing an unsuspecting user, but against a real-time proxy it does not help at all, because the number the attacker's session displays is the number your app shows.

The common factor in every failure above is that the user decides which site is legitimate, and every one of these methods trusts that decision. So the fix has to remove the user from that judgement. Which is exactly what a WebAuthn credential does: the key pair is registered against one relying party identifier, the browser refuses to offer it to any other origin, and the signature covers the origin the browser actually connected to. A look-alike domain gets no credential offered — not because the user noticed, but because the browser did the comparison. There is also nothing to relay: the private key never leaves the authenticator, so there is no readable value for a proxy to forward.

Two honest limits. First, this protects the login, not everything after it. A session token stolen by malware on the device is still a session token, and binding tokens to the client remains rare in practice. Second, account recovery is the usual way back in — an organization that deploys security keys and keeps an SMS-based reset path has reintroduced the hole beside the door it just closed.

c

The analogy

THE ANALOGY #
THE FIGURE

Think of the difference between a spoken door code and a cut key. A code can be repeated to anyone who asks convincingly, including someone standing at the wrong building who then walks to the right one and says it. A key cut for one lock does not turn in a different lock, no matter how persuasive the person asking, and no matter how confidently the wrong door is labelled.

WHERE IT BREAKS DOWN

the analogy makes the defence look like a property of the object, as if the key were merely harder to copy. The real move is that the browser checks which door is in front of it before the key is ever offered — a person holding a key can still be led to the wrong building, but an authenticator cannot, because the comparison happens before the user is asked anything at all.

d

Clarifying the model

THE MODEL #

The misconception worth naming is that phishing resistance is a property of how many factors you have. It is a property of whether any factor can be replayed by a party the user was fooled into trusting. One factor that cannot be relayed beats two that can — and that reordering is uncomfortable, because it contradicts the counting intuition that made "two-factor" a marketing phrase in the first place.

A second refinement: this reframes what "phishing training" can achieve. Training targets the user's judgement about a domain name, and look-alike domains, punycode and compromised subdomains are specifically engineered to beat that judgement under time pressure. Origin binding does not improve the judgement; it makes the judgement irrelevant. Those are different kinds of control, and only one of them degrades when the user is tired.

Finally, a fair word for codes. Against credential stuffing — reused passwords replayed in bulk from a breach dump — a one-time code is highly effective, because that attacker is not present at the moment of login and cannot be. The measure is well matched to that threat and poorly matched to a live proxy. Naming the threat before evaluating the control is the whole discipline here.

e

A picture of it

THE PICTURE #
Why a code sent to your phone does not stop phishing
Why a code sent to your phone does not stop phishing Three requirements sit above three candidate factors, and what matters is which lines exist. All three factors satisfy the first requirement -- the one people count, which is why the picture looks reassuring until you read further. The two high-risk requirements below it have a single line into them. Where a line is absent, the attack works: a code that can be read out can be relayed, and a factor with no origin binding cannot tell the real site from a proxy. {"generator":"[email protected]","source":"../Socrates/.diagram-cache/_src/why-a-code-sent-to-your-phone-does-not-stop-phishing.md","sourceIndex":1,"sourceLine":4,"sourceHash":"b8e5356c893a7fdd3f879b433e2d33d8d24a3d3b9410e891b7d4ed0483707ef3","diagramType":"requirement","layoutVariant":"source","repairedDuplicateIds":[],"motion":"entrance-with-reduced-motion-fallback","presentation":"editorial","attempt":1,"viewBox":{"x":0,"y":0,"width":1256,"height":538},"qa":{"passed":true,"findings":[]}} satisfies satisfies satisfies satisfies satisfies <<Requirement>> SecondFactor ID: 1 Text: a password alone is not enough Risk: Medium Verification: Inspection <<Requirement>> NotRelayable ID: 2 Text: nothing a user can read out and retype Risk: High Verification: Test <<Requirement>> OriginBinding ID: 3 Text: only the real site can use the credential Risk: High Verification: Test <<Element>> SMSCode Type: factor <<Element>> AuthenticatorApp Type: factor <<Element>> SecurityKey Type: factor

How to readThree requirements sit above three candidate factors, and what matters is which lines exist. All three factors satisfy the first requirement — the one people count, which is why the picture looks reassuring until you read further. The two high-risk requirements below it have a single line into them. Where a line is absent, the attack works: a code that can be read out can be relayed, and a factor with no origin binding cannot tell the real site from a proxy.

f

What became clearer

WHAT CLEARED #
WHAT CLEARED

A one-time code is a bearer secret carried by the user, so it inherits the user's judgement about which page they are on — and a real-time proxy makes that judgement the only thing standing in the way. The second factor raises the attacker's cost from "later, in bulk" to "now, while you watch", which is worth something but is not the wall it is sold as. Phishing resistance comes from binding the credential to an origin the browser verifies, because that is the one check a convincing fake page cannot pass.

g

Where to go next

ONWARD #
  • How a passkey is synchronized between devices without the private key becoming relayable, and what that costs in assurance.
  • Why session token theft is the next bottleneck once logins are phishing-resistant, and what binding a token to a device would require.
h

Key terms

TERMS #
TermWhat it means
One-time codea short-lived value proving possession of a phone or seed, presentable by anyone who obtains it in time.
Adversary-in-the-middle phishinga proxy that relays credentials and codes to the real site in real time and captures the resulting session.
WebAuthnthe browser API for public-key credentials scoped to a relying party, whose signature covers the connected origin.
Origin bindinga credential usable only with the site it was registered for, enforced by the browser rather than the user.

Every term the collection defines is gathered in the glossary.

Nearby on the shelf

4