← Back to list

We Reset the Password. We Reset 2FA. The Attacker Came Back in Seconds.

A session hijacking war story, and why the application layer is your last, best line of defense.

Suleyman Musayev · 2026-08-05 13:01 · 0 claps · 5.5 min read
#cybersecurity #session-hijacking #authentication #fraud-prevention #security-engineering
Open on Medium ↗
Wiki topics: 🔒 · Cybersecurity

We Reset the Password. We Reset 2FA. The Attacker Came Back in Seconds.

Photo by Rubén Bagüés on Unsplash

Photo by Rubén Bagüés on Unsplash

A session hijacking war story, and why the application layer is your last, best line of defense.

The ticket looked routine: a customer reporting account activity that was not theirs. Strong password. 2FA enabled. The kind of account that is supposed to be safe. Then I pulled the session logs and found the detail that made this case different: the attacker was logging in seconds after the customer did. Not hours later from some faraway timezone. Seconds. Two sessions, running side by side, as if the attacker was standing right behind the customer and reading the screen over their shoulder.

How we spotted him

If the attacker logs in seconds after the real user, from what looks like the same account, how do you tell them apart?

By the things they did not fake. The attacker’s sessions came from a different IP address and carried a different device fingerprint than the customer’s. Same password, same 2FA, same everything the account was supposed to check, but a different machine on a different network. A careful attacker can spoof both of those signals; this one had not bothered. Once we knew that, the logs stopped being noise. We could point at each attacker session and say: that one is not the customer.

The standard playbook did not help

Every incident responder knows the account takeover checklist. We ran all of it.

  • Password reset — the attacker came back.
  • 2FA reset and re-enrollment — the attacker came back.
  • Forensics on the customer’s computer — Nothing.
  • Enterprise-grade endpoint protection — Installed, scanned, monitored. It found nothing, and the attacker came back anyway.

At this point the software was more confident than we were. I suspected social engineering. The customer said no, firmly. And the evidence was on their side: you do not trick a person into a pattern where every fresh credential is stolen within seconds of its first use.

What the failure pattern tells

Here is a simple rule I learned that month: when you change the lock three times and the thief still walks in, the problem is not the lock. If password and 2FA resets change nothing, the attacker does not have your credentials.

They have something better: your session. And here is the trap in the standard playbook: even when a reset revokes every active session, the customer’s next login mints a fresh one, and whatever stole the last session is still in place to steal this one. You are not evicting the thief. You are refreshing his supply. A login that follows the user by seconds, from another machine, points at real-time session theft. We lined up the candidates and started crossing them off:

  • A keylogger or malware on the customer’s computer, quietly copying cookies or keystrokes.
  • A man-in-the-middle sitting on the customer’s home network, reading traffic between the customer and the site.
  • Sophisticated malware that no scanner had a signature for yet, which would explain the clean forensics.

To test the network theory, we temporarily moved the customer onto a mobile network, away from their usual connection. It helped. That pointed away from a pure server-side problem and toward something living close to the customer, on their device or their network. I will admit one more thing that never made it into any report, because it was neither evidence nor even a real suspicion: the whole case simply felt alive, as if someone had a live view of the screen and was watching the customer move and type in real time. You learn to trust that feeling, then go find the data that earns it. And here is the uncomfortable part: we never got a full confession out of that endpoint. Clean forensics, clean antivirus, and an attacker who kept coming back like a cat you fed once.

That is not a failed investigation. That is the reality of defending users whose devices you do not control. Which brings us to the lesson this incident carved into me:

You cannot always fix the endpoint. But the session is yours.

The session token lives in your application. Your code creates it, your code checks it on every request, your code decides when it dies. If an attacker steals a token, every next move they make still has to pass through you.

What we built

Four mechanisms, all at the application layer.

Session binding. Each session carries a server-side record of the context it was born in, including the IP and device fingerprint that gave this attacker away. On every request, the current context is compared with the stored one, and the difference is scored. The key decision: score, do not pin. If you hard-pin a session to one IP, you lock out every honest user who walks from wifi to mobile data. This is the fine line every security control has to walk: too loose and you protect nothing, too tight and you punish the very people you are protecting. A good measure is tailored so the attacker feels it and the customer never does.

Replay detection. The same token showing up from two different contexts, in a window too short for any airplane, is not a traveling user. It is a copy. We watch for reuse patterns that are impossible for a real person and treat them as compromise, not coincidence.

Automatic termination with step-up. When suspicion crosses the line, we do not send an email and hope. Every session on the account dies immediately, and the next login demands fresh, full authentication. The cost of a false positive: one honest user logs in again and grumbles. The cost of a false negative: an attacker keeps an account they should have lost. That trade is not a hard one.

4. Confirm logins from a new IP. After this case I added a control for the whole platform: if we see a login from an IP address we have never seen on that account, we pause authentication and email the customer to confirm it is really them. A stranger on a new network no longer gets a free pass just because they hold the right password. It is a small ask for the real owner and a wall for everyone else.

A note on tooling: the forensics moved much faster than they would have a few years ago, because I paired an LLM with human judgment. I used it to read through months of logs in minutes, cross-match requests, IP addresses, and device fingerprints, and surface repeated patterns in the requests and URLs the attacker kept touching. The model never gets tired of connecting dots. The human decides which dots are the attack. Detection to mitigation in minutes, not days.

The result

The attacker’s access died and stayed dead. Weeks of password and 2FA resets had failed. So we did not ship one fix and wait. We shipped all of it at once, session binding, replay detection, instant termination, and the new-IP challenge, in a single deployment, to close the hole and kill any further probing in the same breath. Together they ended his access. Then the attacker went silent. I do not think he reformed; I think he simply moved on to probe someone else, the way a burglar who finds one locked house tries the next street. Quiet is not the same as gone. But quiet on your platform, on your watch, is a win you take.

Takeaways

  • If credential resets do not evict an attacker, stop resetting credentials. They have the session, not the password.
  • An attacker who logs in seconds after the user, from a different IP and device, is a session theft signature. Look for concurrent sessions.
  • Clean endpoint forensics does not mean no compromise. It means the compromise is not where you are looking.
  • Bind sessions to context and score the drift. Do not hard-pin IPs. Tailor every control so it bites attackers, not customers.
  • Challenge logins from never-before-seen IPs before you trust them.
  • Make session termination cheap, instant, and account-wide. It is the one lever the attacker cannot take away from you.

I am a software engineer who occasionally has to deal with fraud, abuse and application security. I stop bots, account takeovers, and the occasional attacker who survives a full forensic workup. More at msuliq.github.io.


메타데이터
post_id
17575ad55246
slug
we-reset-the-password-we-reset-2fa-the-attacker-came-back-in-seconds-17575ad55246
url
https://medium.com/@msuliq/we-reset-the-password-we-reset-2fa-the-attacker-came-back-in-seconds-17575ad55246
canonical_url
https://medium.com/@msuliq/we-reset-the-password-we-reset-2fa-the-attacker-came-back-in-seconds-17575ad55246
author_url
https://medium.com/@msuliq
status
ok
fetched_at
2026-08-23 23:14:00