The CAPTCHA most people picture is an image. A pile of fire hydrants. A bus on the third row. A click on a checkbox that maybe takes a second to think.
There is another kind of CAPTCHA that almost nobody sees, because it does not ask the user to do anything. The browser does the work. The user waits, briefly. Then the form submits.
This is the proof-of-work CAPTCHA. The mechanism is older than the modern web — it comes from Adam Back’s Hashcash paper in 1997[1] — but the implementation in a CAPTCHA widget is a recent shape. mCaptcha, Friendly Captcha, and Altcha all use it. Cloudflare Turnstile uses it as one challenge type among several. It is the quietest CAPTCHA on the market, and it is the one I had to look at for longest before I felt I understood it.
What the server asks for
A proof-of-work CAPTCHA is, at heart, a puzzle the server invents on the fly and the browser solves. The puzzle is cheap to verify and expensive to compute.
The shape, stripped to essentials:
- The browser asks the server for a challenge.
- The server returns a random seed and a difficulty parameter.
- The browser searches for a number that, when combined with the seed and hashed, produces a hash whose first N bits are zero. N is the difficulty.
- The browser sends the seed, the number, and the hash back.
- The server hashes seed-plus-number once, checks the result, and either accepts or rejects.
The hash function is normally SHA-256. The number being searched for is sometimes called a nonce (the same word a Bitcoin miner would use, for the same reason).
The asymmetry is the point. Finding a hash that starts with twenty zero bits takes the browser, on average, about a million tries. Checking that a candidate hash starts with twenty zero bits takes the server one SHA-256. The user pays in milliseconds; the server pays in microseconds.
Why anyone thought this was a good idea
If you are a small forum, you do not have hundreds of thousands of user sessions a day to train a behavioural model on. You cannot tell a real Firefox from a headless one by looking at how the mouse moves, because you do not have enough mice to compare.
A proof-of-work challenge does not need any of that. It does not care who the user is. It cares only that whoever is submitting the form is willing to burn a measurable amount of CPU on their side. A real user is willing. A bot farm submitting a hundred thousand requests per hour is not — or rather, it can be made not to be, if you crank the difficulty up.
This shifts the economics. A scraper running on a $5 VPS can post ten thousand spam comments a day if each post costs a TCP handshake. If each post costs eight seconds of CPU at full tilt, the same scraper posts a few hundred. That is often enough.
It also costs the user nothing privacy-wise. There is no fingerprint, no device check, no third-party cookie. The server learns that some browser did the work. It does not learn whose.
Where it stops working
PoW is unfashionable in serious adversarial contexts for a reason: the attacker’s CPU is often as cheap as the defender’s. If you are trying to keep a determined actor out of a high-value account on a big consumer service, you cannot just charge them five seconds of compute. They will pay it. They will pay it in parallel from a thousand machines.
The honest framing is that PoW is a spam defence, not an adversary defence. It works against the long tail of low-effort automation. It does not work against anyone who has decided that getting in is worth real money.
The other thing PoW does not do is help with accessibility much — which is its main pitch against image CAPTCHAs. It does not make a user click anything, true. But on a slow phone, with a high difficulty, the wait is non-trivial. A keyboard user with a screen reader gets through it transparently; a user on a five-year-old Android handset on a flaky network gets to wait fifteen seconds for the form to submit and is not told why.
What I take from this
PoW CAPTCHAs are the quietest, most privacy-respecting option on the market. They are also the least effective against motivated attackers. Whether they are the right pick depends almost entirely on what you are defending: a low-volume contact form, almost certainly yes; a login on a service worth attacking, almost certainly no.
The interesting cases are the hybrids. Cloudflare Turnstile picks the challenge type per request, and a proportion of those challenges are PoW. Friendly Captcha lets you raise the difficulty server-side as you detect suspicious patterns. The proof-of-work piece is not the whole defence; it is one tool in a small bag.
I will be reviewing these services individually over the coming weeks. This post is the background for those reviews.
Back, A. (2002). Hashcash — A Denial of Service Counter-Measure. See references below for the PDF. ↩︎