Korzen

Blog

How to stop fake sign-ups without a CAPTCHA

Fake accounts burn free trials, skew your metrics and seed later abuse. How to tell a scripted sign-up from a real one, and what to do with the answer.

A sign-up form is the cheapest thing on the internet to attack. It takes no password to guess and no card to steal, and every account it creates is worth something to someone: a free trial to resell, a referral bonus to farm, an inbox for spam, or a sleeper account for later fraud. If your sign-ups jumped overnight and your activation rate fell, a script is probably filling the form.

What fake sign-ups cost you

  • Money: free credits, trial compute, SMS and email verification fees, referral payouts.
  • Data: a funnel full of accounts that will never convert hides what real customers do.
  • Reputation: verification emails to made-up or stolen addresses bounce and hurt your sender score.
  • Later abuse: accounts created today are used for spam, scraping or card testing next month.

Why a CAPTCHA is not the answer

CAPTCHA-solving services answer puzzles for well under a cent each, using people or models, so a determined attacker pays a little and walks through. Your real visitors pay the full price: every puzzle loses some of them, more so on phones. A CAPTCHA moves the cost onto the wrong side.

What gives a scripted sign-up away

No single signal is proof, and anything an attacker controls, such as the User-Agent, can be faked. What scripts find hard is being consistent across many signals at once, and behaving like a person over time.

  • Automation flags. Headless and driven browsers still leak: navigator.webdriver, a software GPU, missing browser features.
  • Inconsistencies. A User-Agent that claims Windows on a browser that reports Linux, a timezone that does not match the network, client hints that contradict the headers.
  • The network. Sign-ups from hosting providers rather than homes and phones. On its own this is weak evidence: VPN users are real people too.
  • Fan-out. One device, one token or one subnet creating many accounts in minutes.
  • No page. A request to the sign-up endpoint from a client that never loaded the sign-up page.

Decide on the server, before the account exists

The decision belongs where the account is created, not in the browser where a script can skip it. Before you insert the user, ask for a decision about the request, with a short timeout:

POST /v1/decide
{ "ip": "203.0.113.10", "user_agent": "Mozilla/5.0 …",
  "token": "<_kz cookie>", "path": "/signup" }

Then act on the class you get back, from the most certain to the least:

  • bot high: refuse the sign-up.
  • bot: create the account but hold its trial credits until the email is verified, or ask for a phone number.
  • unknown, human, human high: let it through as usual.

Holding back the reward, rather than blocking the form, is what makes fake sign-ups stop being worth it, without turning away a real customer whose only fault was a VPN.

Fail open

If the check is slow or down, let the sign-up through. A few fake accounts during an outage cost far less than a sign-up page that stops working. We wrote more about this in why a bot check must fail open.