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 verification

5 minutes to integrate. Under 40ms per check. Free at sntlhq.com.