Credential stuffing and login protection: stop the bots, keep the customers.
Credential stuffing detection and login protection: why per-IP limits fail, how to read device and automation evidence at login, and how to step up safely.

Credential stuffing detection is the art of spotting a script that is trying thousands of leaked email and password pairs against your login form, among real customers who simply mistype theirs. The attempts arrive from many addresses, so the evidence that works sits in the device and the automation behind them, read on your server before the password is checked.
This how-to covers the bot-driven side of login risk: why these attacks slip past limits per address, what to read at login, a policy that protects accounts without locking customers out, and where the honest limits are. For the customer-recognition side, see the playbook on account takeover prevention with device signals.
What is credential stuffing, and why is it hard to stop?
Credential stuffing replays passwords stolen from other sites against yours, betting that some people reused them. Nobody has guessed anything. Each attempt submits a real email and a real password, so the request looks like an ordinary login, and the few that succeed are the account takeovers you read about later.
These are malicious bots working at scale. They rotate through proxies, including residential ones that borrow a household connection, so a limit per IP address blocks real customers on shared networks while the attacker moves on. They also go slowly on purpose, spreading attempts over hours to stay under thresholds. That is why login protection that counts only addresses or only failed passwords keeps losing.
Why count devices instead of addresses?
Because an attacker can rent a million addresses far more easily than a million devices. The script behind a stuffing run runs in a limited number of automated browsers or modified clients, and each of them has a recognisable identity. Fingerly returns a visitor ID for the device behind each identification, so you can count login attempts, failures and distinct accounts per visitor ID over a window you choose.
One device trying forty different accounts in an hour is not a family sharing a laptop. A person has one or two accounts, and the same device signs in to the same one repeatedly. Distinct accounts per device is a far stronger signal for bot detection for logins than failed passwords per address, and it survives address rotation.
What does Fingerly report that helps at login?
On every identification, Fingerly reports the evidence of automated traffic and the evidence of disguise, and you read it before deciding. None of it requires the visitor to do anything.
- Automation: browsers driven by an automation framework, and clients that declare themselves a bot or scraper.
- Disguise: browsers whose built-in behaviour has been modified, anti-detect browsers claiming an identity they do not have, and browsers running in virtual machines.
- Thin reports: a visitor that gives away too little to identify anyone is reported as suppressed, which is itself a sign of evasion.
- Activity: a device that is far busier than your own traffic normally is. It is learned for your organisation, environment and platform, and stays in shadow for the first seven days and at least 1,000 samples, so a launch week is not mistaken for an attack.
- Network: Tor exits, datacenter and residential proxies, commercial VPNs, hosting networks and a location that disagrees with the device.
- In apps: emulators, simulators, rooted and jailbroken devices and instrumentation attached to the app.
Each finding carries a weight you control, and the weights add up to a suspect score with a level of low, medium or high. Serious automation hides its obvious flags, so tampering is reported alongside it, because the evidence of having hidden something is harder to remove than the flag itself.
How do you add login risk checks step by step?
Identify on submit, verify by request ID, and decide before touching the password. The order is the point: a script should learn nothing from attempts you refuse.
- Identify when the login form is submitted, with a tag such as login, using the browser or native SDK. If identification fails, carry on and send no request ID.
- Send the request ID to your backend with the credentials.
- On your server, read the stored event by request ID with a secret key, and check that it exists, carries the login tag, is recent and has not been used before.
- Update your own counters for this visitor ID: attempts, failures and distinct accounts in the window you chose.
- Decide first, then check the password. For a refused attempt, return the same generic failure you return for a wrong password.
- Only after a fully successful sign-in, including any second factor, record the device as known for that account.
Fingerly does not see your passwords and does not check them against any leaked list, and the counters live in your database, not ours. It supplies the device identity and the evidence, and you supply the rule.
What should a login policy look like?
Scale the response to the evidence, and keep the cheapest check for the most common case. A starting policy to tune on your own traffic:
- Known device, low level: allow with no extra steps.
- New device, low level: allow, and notify the customer of a sign-in from a new device.
- Medium level, or a device that is trying several accounts: step-up authentication, such as a second factor or an emailed code.
- Automation, a virtual machine or a modified browser: ask for a second factor, or refuse the attempt without saying why.
- High level, or a device trying many distinct accounts in the window: refuse, and keep the attempt in your log.
- No usable identification: ask for a second factor rather than refusing, so customers with hardened browsers are not locked out.
Apply the same table to password resets and to changes of email or phone number with their own tags, because many takeovers begin there. A known device lowers friction, but it is never a reason to skip the password.
What are the limits?
No detector sees every script. A careful attacker can drive a real browser slowly from clean residential connections, and a stolen session can come from the victim’s own device. Device evidence makes bulk attacks expensive and noisy. It does not make a determined, patient one impossible, and it is not a substitute for strong passwords, second factors and breach monitoring on your side.
Shared and corporate networks put many real people behind one address, so treat network signals as context, not a verdict. And keep a recovery path, such as email verification or support, for anyone you challenge, because the customers you get wrong will be the ones who care most.
How do you roll it out without hurting conversions?
Observe, tune, then enforce. For a week or two, log the decision the policy would have made next to what actually happened. Adjust the risk weights and your own limits against that log, enforce the gentle responses first, and tighten only when the numbers justify it. Fingerly can also send the visitor.suspect webhook when an identification reaches the high level, which is a convenient trigger for an alert to your security team.
