Account Takeover (ATO) Prevention: Signals That Actually Work
Account takeover slips past passwords using stolen credentials. Learn which IP, phone, and behavioral signals detect ATO at login and how to respond without blocking users.
Account takeover doesn't break in, it logs in, using credentials stolen from a breach or phished from the user. Because the password is correct, ATO sails past the front door untouched. Stopping it means looking past the credential to the context of the login: where it's coming from, on what network, and how it compares to the account's normal behavior.
How ATO happens
- Credential stuffing: bots replay username/password pairs leaked from other breaches at scale.
- Phishing: the user is tricked into handing over credentials (and sometimes an OTP).
- Session hijacking: stealing an authenticated session token.
Signals that actually catch it
The correct password tells you nothing about whether the person typing it is the real owner. These contextual signals do:
- IP reputation & classification: logins from datacenter IPs, known VPNs, or proxies are disproportionately ATO, especially for accounts that normally connect from residential networks.
- Geo / impossible travel: a login from a new country minutes after one from home.
- New device / fingerprint: an unrecognized device on a sensitive account.
- Phone changes: an attacker swapping the recovery number to a VoIP line is a major red flag.
- Velocity: many login attempts across many accounts from one network signals credential stuffing.
Responding without punishing real users
The art of ATO defense is reacting to risk without adding friction for the 99% of logins that are legitimate. Score the login context; when risk is elevated, step up with an additional factor or a verification challenge rather than a hard block. Save aggressive responses, lockouts, forced resets, for high-confidence cases like a known-VPN login from a new country immediately followed by a recovery-phone change.
const ip = await score("ip_risk", { ip: loginIp });
const risky =
ip.ip_features.known_vpn ||
ip.ip_features.classification === "datacenter" ||
isNewCountry(account, ip.ip_features.geolocation.country);
if (risky) requireSecondFactor(); // OTP, passkey, email confirm
else proceed();Frequently asked questions
Why don't passwords stop account takeover?
ATO uses correct credentials stolen via breaches or phishing, so the password check passes. Detection has to rely on login context, IP, location, device, and behavior, rather than the credential itself.
What are the best signals for detecting ATO?
IP reputation and classification (datacenter/VPN), impossible-travel geolocation, new devices, recovery-phone changes to VoIP numbers, and login velocity indicating credential stuffing.
How do I stop ATO without frustrating real users?
Use risk-based authentication: score each login's context and only step up with an extra factor when risk is elevated, reserving hard actions like lockouts for high-confidence cases.
Try RiskUnified free
Score email, phone and IP risk from one API. 500 free credits every month, no credit card required.