Stopping Fake Signups Without Punishing Real Users
Why bots register for your product, why CAPTCHA is the wrong first move, and a layered signup defense — honeypots, timing, disposable-domain policy, invisible attestation, progressive trust, and measuring the friction you're adding.
Somewhere between launch and your first thousand users, the fake accounts arrive. Sometimes it is obvious — a thousand registrations in an hour, all firstnamelastname####@gmail.com. Sometimes it is subtle: a slow trickle of accounts that verify their email, sit idle for a week, and then start posting links.
The instinct is to add a CAPTCHA. This is understandable and usually the wrong first move, because it imposes measurable cost on every real user to impose a cost of roughly $0.001 on the attacker. There are better places to start.
Why bots want your account
The defense depends entirely on the motive, so start here.
Free resources. Trial credits, API quota, storage, compute. Anywhere a free tier has value, someone will farm it at scale. This is now a major driver of automated signup, and it is entirely rational.
Sending reputation. Your transactional email goes out from your authenticated domain and reaches inboxes. An account that can trigger emails containing attacker-chosen text — an invitation with a custom message, a share notification, a "someone mentioned you" — is a laundering service for spam that would otherwise be filtered.
SEO and link placement. Any user-generated content that renders publicly is a backlink target. Profile bios and public pages get farmed relentlessly.
Staging for a later attack. Aged accounts are more trusted by your own heuristics. Register now, sit quiet, act in three months when the account looks established.
Metric pollution. Less malicious, equally damaging: your activation funnel, your cohort retention, and your growth numbers become fiction. Teams have made real strategic decisions on data that was mostly bots.
Denial of service by namespace. Squatting on usernames, subdomains, or organization slugs.
Knowing which of these applies tells you where to put the friction. Free-tier farming is best stopped at resource grant, not at registration. Spam-relay abuse is best stopped at first send. Applying all your friction at the registration form is usually the wrong placement.
Start with the cheap invisible layers
These cost real users nothing and eliminate a surprising share of unsophisticated automation.
Honeypot fields. A form field hidden from humans by CSS, with autocomplete disabled. Naive bots fill every field they find. Anything that submits a value is rejected.
<div class="hp" aria-hidden="true">
<label for="company_website">Company website</label>
<input type="text" id="company_website" name="company_website" tabindex="-1" autocomplete="off">
</div>
<style>.hp { position: absolute; left: -9999px; }</style>
Use position: absolute; left: -9999px rather than display: none — some bots have learned to skip explicitly hidden inputs. Never use a name like honeypot. And take aria-hidden and tabindex="-1" seriously: without them you have built a form that screen reader users will fill in and be rejected for.
Submission timing. Sign a timestamp into the form on render and check the elapsed time on submit. A form completed in under two seconds was not typed by a person. Reject the impossibly fast; do not reject the slow, because real people get distracted. The timestamp must be signed or held server-side, or it is just another field the bot controls.
Required client-side work. Have the page compute something trivial in JavaScript and submit the result. This does not stop a headless browser, but it does stop the enormous volume of pure HTTP-client automation that never executes JavaScript. Nearly free, and it is the layer that removes the noisiest attackers.
A proof-of-work challenge. Require the client to find a hash with a given prefix before submitting — a few hundred milliseconds of CPU, invisible to a real user, and a genuine cost multiplier at a million registrations. This is the mechanism behind privacy-preserving CAPTCHA alternatives, and it has the pleasant property of imposing cost without imposing interaction.
Then invisible attestation
Modern challenge systems — the invisible modes of reCAPTCHA and Turnstile, and platform attestation APIs — run without user interaction in the overwhelming majority of cases and return a score or a pass/fail based on signals the page can gather.
Two things determine whether these help or hurt.
Never gate on the score alone. Treat it as one input among several. A user on a privacy-focused browser, a VPN, or a corporate network will score badly while being entirely genuine. If a low score blocks registration outright, you have chosen to reject a real, privacy-conscious segment of your market.
Verify server-side, always. The client receives a token; your server exchanges it with the provider. A client-side check is decorative — the bot simply does not run it.
An interactive challenge should be the escalation, shown to the small population that fails the invisible layers, not the default experience.
The disposable email question
Blocking disposable email domains is the most-requested and most-overrated signup control.
The problems are real. The domain lists are enormous, always stale, and updated by services that add domains faster than any list can track. They produce false positives on legitimate small providers and privacy-forwarding services — and blocking Apple's iCloud private relay, or a mail-forwarding service a user relies on, rejects real customers with real money. And it is trivially bypassed: the attacker registers a domain for a few dollars and now has infinite addresses that appear on no list.
The result is a control that inconveniences privacy-conscious real users and does not stop a motivated attacker. A better set of rules:
Do check MX records. A domain with no mail exchanger cannot receive mail, so an address there can never be verified. This is a fact, not a heuristic, and it costs one DNS lookup.
Do use disposable-domain detection as a risk signal, not a block. A disposable address contributes to a risk score that might require additional verification. It does not by itself reject.
Do consider your product. For a B2B SaaS selling to companies, requiring a corporate domain is a legitimate product decision, not merely an anti-abuse measure — and it should be presented that way. For a consumer product it is an unacceptable loss of signups.
Do not attempt SMTP verification. Connecting to the mail server to probe whether an address exists is unreliable, frequently gets your IP blocklisted, and is itself the behaviour of a spammer.
The stronger version of this control lives one step later anyway: an unverified account should be unable to do anything worth doing, which is the email verification gating problem.
Progressive trust: the actual answer
The most effective structural change is not a better filter at the door. It is to make a fresh account worth very little, so that the economics fail regardless of how the account was created.
Grant capability as a function of demonstrated legitimacy rather than at the moment of registration:
| Stage | What the account can do |
|---|---|
| Registered, unverified | Look around. Nothing outbound, nothing public, no resources. |
| Email verified | Core product use. Small quotas. |
| Verified + 24h age | Public content, invitations, higher quotas. |
| Payment method on file | Full quotas, API access. |
| Established history | Elevated limits. |
This works because it inverts the attacker's cost model. Registering ten thousand accounts is cheap; getting ten thousand accounts to a state where they can actually send mail or consume meaningful compute is not — and every step gives you another observation point to catch them at. It also removes the pressure to be aggressive at signup, which is where friction hurts your conversion most.
The corollary is that abuse detection belongs at the point of value extraction, not at registration. Rate-limit outbound sends per account age. Cap free-tier resources by trust stage. Require verification before public content is indexable. The signup form is the wrong choke point for almost everything.
Detecting the patterns humans do not produce
Individual signups can look perfect. Populations of signups do not, and that is where the signal is.
- Registration velocity by IP, subnet, and ASN. Individual IPs rotate; ASNs rotate far less.
- Email address structure. A cohort of addresses sharing an unusual pattern, or Gmail dot/plus permutations resolving to one mailbox.
- Timing regularity. Humans register in a diurnal pattern. Automation is often uniform across the clock, or arrives in bursts too regular to be organic.
- Password reuse across new accounts. Different accounts, same password hash, same day. Extremely strong signal, and easy to compute.
- Identical request fingerprints. Same header ordering, same TLS fingerprint, same viewport, across hundreds of "different" users.
- Referrer uniformity. Everyone arriving from nowhere, or from the same unusual source.
Run these as a batch job over recent registrations rather than as a synchronous check. Retroactive suspension of a cohort is far more effective than trying to catch each one at the door, and it does not add a millisecond of latency to a real user's signup.
Measure the friction you are adding
Every control here has a cost, and most teams never measure it. Before and after any change:
- Signup completion rate, by step. The step where people leave tells you which control is expensive.
- Time to complete the form.
- Challenge rate — what fraction of real users are seeing an interactive challenge. If it exceeds a few percent, your thresholds are wrong.
- Support volume about being unable to register. These tickets represent the users who bothered to complain; most just leave.
- False positive rate, sampled by hand. Pull fifty rejected signups a week and look at them. This is unglamorous and it is the only way to know whether your filter is rejecting customers.
The metric that matters is not "fake accounts blocked." It is fake accounts blocked per real user inconvenienced. A control with a great absolute block count and a 3% false positive rate is destroying more value than it protects.
Key takeaways
- Identify the motive first. Free resources, sending reputation, SEO, aged accounts, and metric pollution each want friction in a different place.
- Start with the free invisible layers: honeypots done accessibly, signed submission timing, required client-side work, proof-of-work.
- Use invisible attestation as one score among several, verified server-side. Never as a hard gate.
- Disposable-domain blocking is overrated. Check MX records; treat disposability as a risk signal, not a rejection.
- Progressive trust is the structural fix — make a fresh account worth almost nothing, and enforce at the point of value extraction rather than at registration.
- Detect populations, not individuals, in a batch job. Retroactive cohort suspension beats synchronous perfection.
- Measure fake accounts blocked per real user inconvenienced, and hand-review your false positives weekly.
Written by
Emilian GheoneaSenior Blockchain & Full-Stack Software Engineer. I build EmbedAuth — an embeddable authentication platform for SaaS — and write about the auth problems most teams hit too late.
Related articles
Security
Webhook Signatures: Verifying What Your Server Is Told
A webhook endpoint is an unauthenticated API that changes your data. How to sign and verify properly — HMAC over the raw body, timestamps and replay windows, constant-time comparison, key rotation, and the idempotency and SSRF issues on both sides.
Aug 3, 2026 8 minReadSecurity
Audit Logs for Authentication: What to Record Before You Need It
The events every auth system should log, the schema that makes them queryable, why application logs are not an audit trail, tamper-evidence and retention, and how to expose logs to customers without leaking other tenants' data.
Aug 2, 2026 8 minReadSecurity
Credential Stuffing: Why Your Login Page Is Someone Else's Business Model
How stuffing attacks are actually run in 2026 — combo lists, residential proxies, config files and solver services — and the layered defenses that work, from breached-password checks to risk scoring and the metrics that reveal an attack in progress.
Jul 31, 2026 8 minReadSecurity
Protecting Auth Endpoints: Rate Limiting and Brute-Force Defense
How to design rate limiting for login, OTP, and reset endpoints — algorithms, what to key on, lockout strategies, and avoiding the traps that let attackers through or lock out real users.
Jun 12, 2026 8 minRead