PrivCaptcha.com

Credential stuffing and brute force protection for logins

A combo list from someone else's breach, replayed one pair at a time against your login form.

How a credential stuffing run works

A loop over email:password pairs, POSTing each to the login endpoint. Funded kits drive a real browser and rotate residential exit addresses, so per-IP limits never bite.

What credential stuffing looks like in your logs
Failed logins rise and distinct usernames rise with them.
Many attempted usernames have never existed in your user table.
Login success rate drops to a fraction of a percent.

How PrivCaptcha stops credential stuffing

Four steps, with the numbers the server uses. Nothing here is configured by you.

One token per pair, spent once

A solved puzzle mints a token and the verify spends it. A million pairs needs a million challenges.

What the run scores on arrival

A bare HTTP client with bot user-agent and no Accept-Language scores 20+40+15=75, level 4: 10 degrees, 6 pixels, 10 shapes.

Missed puzzles compound to level 4

Misses add 8 each, capped at +40. Five misses take that profile from 20 to 60, level 4: 10 degrees, 6 pixels.

Proof-of-work priced off the score

Proof-of-work scales with risk: 14 bits at 20, 18 bits at 75. It is checked first, so the work is spent on wrong answers too.

What a credential stuffing run costs now: A million-pair list at a half-percent hit rate yields 5,000 working accounts and 995,000 failures. All million need their own challenge and proof-of-work search.

Add PrivCaptcha to your login form in two lines of code

Script tag, container in front of the submit button, and your existing verify call. Already on reCAPTCHA or hCaptcha? That backend code stays exactly as it is.

reCAPTCHA siteverify hCaptcha siteverify
Server SDKs
<!-- login form -->
<script src="https://privcaptcha.com/1/api.js" async defer></script>
<div class="privcaptcha" data-sitekey="your-site-key"></div>
<!-- server side, unchanged -->
POST https://privcaptcha.com/api/v1/siteverify
Where it goes

Inside the login form, so privcaptcha-response posts with the username and password.

What the backend does

The login handler verifies the token against /api/v1/siteverify before any password comparison.

The usual mistake

A re-rendered form carrying the old privcaptcha-response gets invalid-input-response. Reset the widget on every failed login.

What this does not solve about credential stuffing

This is a price, not a cap. A correct pair still passes. Lockout, breached-password checks and MFA remain yours. Rotating residential exits resets the daily counter.

Common questions about credential stuffing

How PrivCaptcha prices credential stuffing, and what it does not do about it.

No, it complements it. Rate limits are per-IP, and a large NAT puts thousands of real users behind one address, so a tight limit locks out a campus rather than stopping a botnet. The puzzle and proof-of-work price each attempt instead, whoever it comes from.
Not for their neighbours' behaviour alone. Scoring leans on what the request itself reveals plus that client's own recent failures, and a track record of solving lowers the score again.
Every request is challenged - there is no invisible pass to aim a script at, and no allowlist that skips the check. What changes is the form the challenge takes and what it costs. The server scores each request and picks one of five difficulty levels, so an ordinary visitor gets a couple of seconds and a client that looks automated gets tight tolerances and a heavier proof-of-work. On the non-visual path, taken by screen-reader and keyboard visitors, there is no puzzle to solve at all: the proof-of-work is the whole challenge, at a fixed 22 bits.
No. An address is used for the length of one request and never written anywhere. What we keep is an HMAC of it under a salt that is random, lives only in Redis and rotates every day, so yesterday's hashes cannot be linked to today's. The counters under that hash expire after 24 hours.

Put PrivCaptcha in front of your login form

10,000 verifications a month are free, and the integration is the one you already have.