Credential stuffing is when attackers take username/password pairs leaked from one breach and try them on your site. With 26 billion credentials leaked in 2025 alone, every login page is a target.
Why It Works
65% of people reuse passwords across sites. If someone's Netflix password leaked, attackers will try it on your platform. They use automated tools that:
- Rotate through millions of stolen credentials
- Use residential proxies to avoid IP-based blocking
- Use antidetect browsers to bypass fingerprinting
- Solve CAPTCHAs automatically with AI
- Mimic human behavior patterns
What Doesn't Work
Rate limiting by IP: Attackers use thousands of residential proxy IPs. Each IP only makes 1-2 attempts — below your threshold.
CAPTCHAs: AI solves them. Services like 2Captcha handle the rest at $2/1000.
WAFs (Cloudflare, AWS WAF): Good for DDoS but miss low-and-slow credential stuffing through residential proxies.
What Works
The most effective defense combines:
- Device intelligence: Detect headless browsers, antidetect tools, and automation frameworks before the login attempt
- Network intelligence: Flag VPN, proxy, and residential proxy connections
- Breach database checking: Reject passwords that appear in known breaches (Sentinel uses Have I Been Pwned with k-anonymity)
- Account lockout: Lock accounts after repeated failures, but per-device, not just per-IP
- 2FA: The ultimate defense — even with the right password, attackers can't get past TOTP codes
How Sentinel Protects Login Pages
Sentinel evaluates every login attempt across two dimensions:
Before authentication: The SDK token is submitted alongside the login form. Sentinel checks the connection for VPNs, proxies, bots, and antidetect browsers. Suspicious connections are blocked before the password is even checked — preventing credential validation.
After authentication: Even if the password is correct, accounts with 2FA enabled require a time-based code from the user's authenticator app.
Implementation
// In your login handler
const sentinel = await fetch('https://sntlhq.com/v1/evaluate', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk_live_YOUR_KEY' },
body: JSON.stringify({ token: req.body.sentinelToken })
});
const { isSuspicious } = await sentinel.json();
if (isSuspicious) {
return res.status(403).json({ error: "Suspicious login blocked" });
}
// ... proceed with normal password verification5 minutes to integrate. Under 40ms per check. Free at sntlhq.com.