A client sent me a screenshot last month. Subject line: "Reset your password." The sender's name looked right. The logo looked right. He asked me, "Is this real?"
It was real. That was the problem.
I spent about twenty minutes going through his account's reset flow after that, not because I thought his email was fake, but because I wanted to check something I'd been putting off for a while: what does the reset link itself actually protect, and what does it just assume?
Turns out, not much is protected by default. A password reset email is one of the most trusted messages a person receives, and it's also one of the easiest things in a login system to quietly break.
The Reset Email Isn't a Security Feature. It's a Convenience Feature.
Here's the part most people get backwards.
A password reset flow was never designed as a security control. It was designed to solve a support problem: too many people forgetting passwords and clogging up help desks. Someone, at some point, decided "just email them a link" was faster than making them call in.
That design choice is now sitting underneath almost every account you own. And most reset systems still trust three things they shouldn't automatically trust:
- That whoever clicks the link is the account owner
- That the link can't be predicted, guessed, or reused
- That the email itself can't be intercepted, redirected, or spoofed
Attackers don't need to "hack" your password. They just need to find the weak assumption in that chain.
Also Read: Why a Correct Password Can Still Get Rejected
What I've Actually Seen Get Abused
I've tested reset flows on client sites for a few years now, mostly small business platforms and WordPress-based shops. These are the patterns that show up again and again — not theoretical, things I've personally triggered or found sitting open.
1. The Reset Link Doesn't Expire (Or Expires Way Too Late)
I found a site once where a password reset token was still valid eleven days after it was generated. Nobody noticed because nobody expected to test it.
If a reset link sits in an old email, an inbox that got breached separately, or a shared computer's browser history, that link is a live password reset waiting to be used — whenever the attacker gets around to it, not just when it was sent.
What a safe window looks like: 15 to 60 minutes. Anything measured in days is a red flag if you're the site owner, and a risk you should assume exists if you're the user.
2. The Token Is Guessable
This one surprised me the first time I saw it. A reset link should contain a long, random, unique string — something like ?token=8f42a1c9d7b3.... I've seen sites use something closer to a sequential number, or a token built from predictable pieces like the account's user ID plus a timestamp.
If an attacker can guess or brute-force that token pattern, they don't need your email at all. They can generate a valid reset link for your account directly.
3. Password Reset Poisoning (Host Header Attacks)
This is the one that actually made me sit up straight the first time I understood it.
When your site sends a reset email, it builds the link using the domain name from the request itself, not a fixed value the server already knows. Some servers trust whatever "Host" the browser claims to be, instead of hardcoding their own real domain.
An attacker can manipulate that request so the email your real system sends contains a link pointing to their domain instead of yours. You get a completely legitimate email, from the real sending system, with a poisoned link sitting inside it.
I confirmed this on a staging environment during a test, not a live client site, and it genuinely worried me. The email headers looked clean. Only the link was wrong.
4. Leaking the Token Through the Referrer
Reset pages sometimes load outside scripts, tracking pixels, or ad network code — the same as any normal webpage. If the reset token sits in the page URL and the page also loads third-party resources, some browsers will send that full URL, token included, to whatever external service just got called.
That token now exists somewhere it was never supposed to travel. It's not usually intentional theft. It's sloppy page design leaking something sensitive as a side effect.
5. Reset Requests Used as a Flood, Not a Break-In
I've also seen the reverse approach, where the goal isn't to steal a password but to make someone's inbox unusable. Automated tools hammer the "forgot password" form repeatedly, and the target gets buried under reset emails.
Sometimes this is a distraction technique, timed right before something else happens on the account. Sometimes it's just harassment. Either way, if you suddenly get a wave of reset emails you didn't request, that itself is the incident — not a glitch.
6. Lookalike Domains in the "Reset Now" Button
The simplest one, and still the most common in practice. The email looks correct because the visible text says yourbank.com, but the actual link underneath points somewhere like yourbank-secure-login.com or a domain with one swapped letter.
I still tell every client the same thing: read the actual destination, not the button text.
The Mistake I Made While Testing This
I'll be honest about something. Early on, while checking a client's reset flow, I generated several test reset tokens back-to-back on a live account to see how long they stayed valid. I didn't think about it until later: I'd left three separate active reset links sitting unused, on an account that wasn't fully isolated from production yet.
Nothing happened. But it taught me something uncomfortable — every reset request you generate is a live key that exists until it's used or expires. Testing carelessly creates the exact exposure you're trying to find. Now I generate one token at a time, and I invalidate it manually the moment I'm done, instead of letting it sit.
Quick Reference: Reading a Reset Email Like a Skeptic
| What to check | Why it matters |
|---|---|
| Hover the button, read the real URL | Visible text can say anything; the link is the truth |
| Did you actually request this? | Unrequested resets can signal someone trying your account |
| How long has it been since you clicked? | An old, still-working link means expiry isn't enforced |
| Does the domain match exactly? | One extra word or hyphen is enough to redirect you |
| Are you on public or shared Wi-Fi right now? | Session hijacking is easier on unsecured networks |
What Site Owners Can Actually Do About This
If you run a website (Blogger, WordPress, a custom app, doesn't matter), a few concrete habits close most of this gap:
- Expire tokens fast. 15–60 minutes, not hours or days.
- Invalidate the token the moment it's used once. A reused reset link should fail every time after the first successful use.
- Hardcode your domain server-side when building reset URLs. Never build the link from request headers you don't control.
- Rate-limit the "forgot password" form. Cap how many reset emails one account (or one IP) can trigger per hour.
- Send a confirmation notice after a successful reset, separate from the reset email itself, so the real owner finds out even if they weren't the one who did it.
- Keep reset pages free of third-party scripts that could leak the token through a referrer header.
None of this requires an enterprise budget. Most of it is a couple of hours of configuration, and I've fixed all six of these on client sites that were running on shared hosting with zero security team behind them.
Also Read: Why Websites Log You Out Automatically After Some Time
What Users Can Do, Realistically
You're probably not going to audit a company's backend. But you can still cut your own exposure down:
- Don't click reset links from an email you didn't ask for. Go to the site directly and request a fresh one yourself.
- Use a password manager so you're never guessing which "reset" is legitimate — the manager won't autofill on a spoofed domain.
- If a reset email shows up out of nowhere, change that password anyway, from the real site, even if you never clicked the link.
- Turn on two-factor authentication wherever it's offered. A stolen or hijacked reset link is far less useful if there's a second step behind it.
Final Thoughts
The thing that stuck with me after that client's screenshot wasn't the phishing attempt itself — those are everywhere, and most people spot the obvious ones now. It was realizing how much trust we've quietly stacked onto a feature that was originally built for convenience, not defense.
A password reset link works fine, right up until someone finds the one assumption it was built on and quietly steps around it. Most of the fixes aren't complicated. They just require someone to actually go check, the way I did for that client, instead of assuming the reset flow was solved years ago and never touched again.
I still test my own client sites' reset flows every few months now. It takes fifteen minutes, and every time, I find at least one thing worth tightening.


comments