Skip to content
nviaOTP

Phishing-Resistant Auth · Chapter 1 of 5

Why phished OTPs break authentication

Real-time relay phishing turns any typed code into the attacker’s code. Understand the mechanics so you stop expecting shorter windows to help.

6 min read

Series 1 ended with a verifier that is one-time, rate-limited and safe under concurrency. It is a good verifier. It is also completely defeated by a phishing page that costs an attacker an afternoon to build. This chapter explains why, precisely enough that you can recognise which defences help and which only feel like they help.

The relay, step by step

An adversary-in-the-middle phishing kit is a reverse proxy. The victim visits a lookalike domain — say larkspur-ledger-secure.example instead of larkspur.example — and the proxy forwards every request to the real site and every response back to the victim, rewriting links as it goes. The victim sees the genuine login page, pixel for pixel, because it is the genuine login page, fetched live. They type their password; the proxy forwards it. The real site asks for a TOTP code; the proxy shows that prompt; the victim types the code; the proxy forwards it within milliseconds. The real site sets a session cookie, and the proxy keeps it.

Every message the real site receives is valid. The code is fresh, unused and typed by the legitimate user — it is simply delivered by the wrong party.

Look at the verifier from series 1 during this attack. The code was generated from the right secret. It was submitted inside the window. It had never been used. The attempt counter was at zero. Every check passes, because the verifier is answering the question it was built to answer — does this code match? — and the answer is yes. The question it cannot answer is which site did the user think they were talking to?

Why shorter windows do not help

A natural reaction is to tighten the TOTP window, shorten SMS code lifetimes or reduce the step to fifteen seconds. Relay latency is measured in hundreds of milliseconds. A kit that forwards a code within half a second is unaffected by a window of thirty seconds, fifteen seconds or five. Windows defend against stored codes being replayed later; they do nothing against codes forwarded in real time.

The same reasoning applies to longer codes, to app-generated rather than SMS-delivered codes, and to push notifications that ask the user to tap Approve. A push approval is just a one-bit OTP, and attackers relay it by triggering the push at the moment the victim expects one. Number matching — where the user types a number shown on the login page into the push prompt — raises the bar against blind fatigue attacks, but a relay proxy shows the victim the real number, so it does not stop relay.

What the attacker actually wins

The prize is not the code, which is worthless seconds later, but the authenticated session. Once the proxy has the cookie it can drop the victim and act as them until the session expires. This shapes defence: shorter session lifetimes, binding sessions to device keys, and re-authentication for sensitive actions all limit the value of a stolen session even when the login itself was phished.

A worked timeline from the bench, an illustrative example: at 2026-09-30 10:02:14 UTC, a finance analyst named Rhys Okonjo opens a link to an invoice portal lookalike. At 10:02:31 he submits his password, at 10:02:44 his TOTP code. At 10:02:45 the attacker’s automation calls the real site’s API to add a new payout destination. The total exposure window during which a shorter TOTP step could have mattered was under one second.

Defences that do and do not work

  • Do not work against relay: shorter windows, longer codes, SMS vs app, push approval, number matching, CAPTCHA.
  • Raise cost but do not solve: device fingerprinting, IP and ASN reputation, impossible-travel checks — the proxy can run near the victim.
  • Limit damage: short sessions, step-up for sensitive actions, out-of-band confirmation of payout changes.
  • Solve the core problem: authenticators that cryptographically bind their response to the origin the browser is actually on.

The last line is the subject of the next chapter. The insight is that the browser knows, with certainty backed by TLS, which origin the page came from. A user does not. If the authenticator’s response includes that origin in a way the real site can verify, a response produced on the phishing domain is useless on the real one — no matter how quickly it is relayed.

Where OTP still belongs

None of this means OTP is worthless. It defeats credential stuffing, password reuse and offline password theft, which are a large share of real account takeovers. It works on every phone without enrolment ceremonies. For many accounts and many actions, it is a reasonable control. The point is to be accurate about its ceiling: OTP raises the cost of attacks that do not involve the user, and does very little against attacks that trick the user in real time. Chapter 5 builds a ladder that uses OTP where it fits and requires origin-bound factors where it does not.

If you remember one sentence from this chapter, make it this: any secret a human can read and type can be read and typed into the wrong place. Phishing resistance therefore cannot come from the secret itself. It has to come from something the human is not involved in.

This also explains why phishing campaigns that target OTP-protected accounts have become routine rather than exotic. The kits are open source, the hosting is cheap and the success rate does not depend on the code type.

0/3 correct · 0 answered

  1. 1. A relay proxy forwards a TOTP code 0.4 s after the victim types it. Which change stops the attack?

  2. 2. What does the attacker ultimately capture in an AiTM phish?

  3. 3. Number matching on push approvals mainly defends against…

Discussion

Comments are public and shared with every reader. No account needed — just a display name. Comments reported by three readers are hidden automatically.

15 more characters needed

Loading comments…