The account lifecycle is where authentication actually breaks
Most teams test the login form. The weaknesses tend to live in password reset, email change, OTP verification and session termination: the parts built later.
Ask a team how they test authentication and you will usually hear about the login form: rate limiting, password policy, maybe multi-factor. The login form is rarely the problem. It is the most looked-at screen in the product.
The problems live in everything around it: the flows that were added later, often under deadline, usually by someone who was not in the room for the original design.
Registration and verification
Can an account be used before its email address is verified? If yes, what can it do? A surprising number of applications let an unverified account invite team members, start a trial, or occupy a username permanently.
The related issue is pre-registration: someone signs up with an email address they do not own, and when the real owner later registers or is invited, the two accounts collide in a way that grants access.
Password reset
Reset flows fail in familiar ways, and they are worth testing individually:
- Tokens that do not expire, or expire far too late
- Tokens that stay valid after they have been used once
- Tokens that are not bound to the account they were issued for
- The reset link leaking through the
Refererheader to third-party analytics - Host-header injection changing the domain in the reset email
- No invalidation of active sessions after a successful reset
That last one matters more than it looks. If an attacker had a session and the victim resets their password to recover the account, the attacker should be logged out. Often they are not.
OTP and one-time codes
One-time codes fail on the details:
- Codes that are short, predictable, or generated from a weak source
- No limit on verification attempts, so the code can simply be brute-forced
- No limit on requests, so codes can be flooded to a victim's phone
- Codes that remain valid after a new one is issued
- The verification response differing enough to confirm whether an account exists
Email and phone change
Changing the address on an account is a privileged action. It should require re-authentication, it should notify the old address, and it should not take effect until the new address is confirmed. When it does not, an attacker with a borrowed session can quietly move the account out from under its owner.
Session termination
The last one is the least glamorous and the most commonly broken: what actually happens on logout? Is the server-side session destroyed, or is the cookie just cleared in the browser? Are other devices signed out when the password changes? Is there any way for a user to see and revoke active sessions?
How to test this properly
Map the lifecycle as a state machine: registered, unverified, active, locked, reset-in-progress, deleted, and then try to reach each state from a state you should not be able to reach it from. Most of the interesting findings are transitions nobody drew on the diagram.
None of this requires exotic tooling. It requires treating the account not as a login form, but as an object with a life cycle, owned by someone who is not you.