← Blog

How to detect and stop fake account signups

Fake-signup defense comes in two layers — gates you build yourself and signals you call for — combined into a graduated allow, step-up, review, or block.

Contents

Most fake signups are not sophisticated. They are scripts filling a form as fast as the network allows, using throwaway email addresses, from wherever a cheap proxy happens to land. You can stop a lot of them with code you already know how to write, and you can stop more by adding a few signal checks that need data you do not have on hand. The trick is to layer the cheap defenses under the paid ones, and to be honest with yourself about what each layer actually proves.

Two kinds of defense

There are gates you build and signals you call for, and it pays to keep them straight.

Gates are logic that lives in your signup handler: a honeypot field, a per-IP velocity limit, a required email-confirmation step. They cost nothing per request, they run before you spend a cent, and no vendor can build them for you because they depend on your form, your traffic, and your tolerance for friction. Boundstone does not do rate-limiting, honeypots, or device fingerprinting. You build those.

Signals are facts about the values a user submitted that you cannot derive locally: whether an email domain is a known disposable one, whether a phone number is even a plausible number, whether an IP is a routable public address or something reserved. That is the layer Boundstone provides. Lead with the gates — they catch the laziest bots for free — and reach for signals when a gate is not enough.

Gates you build

A honeypot is a form field that humans never see and bots usually fill. Add an input, hide it with CSS (not type="hidden" — some bots skip those), and reject any submission that arrives with it populated. It is a few lines and it catches a surprising share of dumb automation.

A per-IP velocity limit counts signups from one address over a rolling window and throttles above a threshold. Keep the counter in whatever you already run — Redis, a database row, a Durable Object. This is yours to tune; a vendor cannot know that ten signups a minute is normal for your enterprise SSO and alarming for your consumer app.

Neither gate needs an API. If honeypots plus velocity limits plus email confirmation already hold your fraud to a level you can live with, stop here. You do not need to buy anything.

Signals you call for

When the gates leak, three cheap signals narrow the field. Each is a single request, and each returns a checks object listing exactly what was and was not verified — so you know the boundary of the signal, not just its verdict.

Disposable email. POST /v1/verify/email returns disposable, role_account, free_provider, and mx_found. Its checks.performed is ["syntax","mx","disposable_list","role_list"]; its checks.not_performed is ["smtp_mailbox","catch_all"]. Read that second list carefully: a positive result — valid_syntax true, mx_found true — means the syntax parsed and the domain has mail exchangers, not that the mailbox exists. Boundstone does not knock on the mailbox and does not detect catch-all domains. Spot-check a single address with the keyless /tools/email-validator before you wire anything.

Phone plausibility. POST /v1/verify/phone returns valid, line_type, and country, with checks.performed ["format","region","line_type_metadata"] and checks.not_performed ["carrier_lookup","ported_status","hlr_liveness"]. That tells you whether a number is shaped like a real number for its region — not whether it rings. Carrier lookup and HLR liveness are a paid opt-in (hlr:true, 5 credits) — never something this endpoint fakes.

IP classification. POST /v1/verify/ip returns classification, is_public, and is_bogon, with checks.performed ["format","version","range_classification"] and checks.not_performed ["geolocation","asn","hosting_datacenter","proxy_vpn_tor","reputation"]. A signup whose source IP classifies as private, reserved, or bogon is worth a second look — those addresses have no business originating public traffic. Note what is absent: Boundstone does not do geolocation, proxy/VPN/Tor detection, or IP reputation. That needs licensed data it has not shipped. This signal is plausibility, not a threat verdict.

Combine them into a graduated response

Do not treat any one signal as a yes-or-no verdict. Score them, and map the score to a graduated action:

  • Allow — gates pass, all signals clean.
  • Step up — one soft signal (a free-provider address, a role account): require email confirmation or a second factor.
  • Review — two or more signals, or a phone that will not parse: queue for a human or a slow lane.
  • Block — honeypot filled, or a bogon source IP paired with a disposable email: refuse.

A single disposable address is a nudge, not a conviction. Reserve "block" for the combinations that leave no honest doubt.

Wiring it together

The gates run first and cost nothing; the API calls run only for submissions that clear them. Keep the bs_live_ key server-side — it is a secret, never a value in a browser or a form field.

// server-side signup handler
export async function handleSignup(req) {
  const { email, phone, honeypot } = await req.json();
  const ip = req.headers.get("cf-connecting-ip");

  // Gate 1: honeypot — you build this
  if (honeypot) return decision("block", "honeypot");

  // Gate 2: per-IP velocity — you build this too
  if (await tooManyFromIp(ip)) return decision("block", "velocity");

  // Signals: you call for these
  const auth = { Authorization: `Bearer ${process.env.BOUNDSTONE_KEY}` };
  const [e, p, i] = await Promise.all([
    post("/v1/verify/email", { email }, auth),
    post("/v1/verify/phone", { phone }, auth),
    post("/v1/verify/ip", { ip }, auth),
  ]);

  let score = 0;
  if (e.disposable) score += 2;
  if (e.role_account) score += 1;
  if (!p.valid) score += 1;
  if (!i.is_public || i.is_bogon) score += 2;

  if (score >= 3) return decision("review", "signals");
  if (score >= 1) return decision("step_up", "signals");
  return decision("allow", "clean");
}

post, tooManyFromIp, and decision are all yours; Boundstone supplies the three verdicts and nothing else. For the full scoring model — weights, thresholds, and how to fold the checks arrays into one confidence read — see the multi-signal walkthrough.

The short version

Build the free gates first: a honeypot, a per-IP velocity limit, email confirmation. They catch the lazy bots and cost nothing. Add signal checks — disposable email, phone plausibility, IP classification — for what the gates miss, and read every checks.not_performed list so you know what each verdict does and does not prove. Score the signals instead of trusting any one, and map the score to allow, step up, review, or block. Boundstone gives you the signals; you build the gates. The full pattern lives in the signup-fraud use case.

Frequently asked questions

How do I detect fake or disposable email addresses at signup?

Check each signup email for valid syntax, a working MX (mail-exchanger) DNS record, whether its domain appears on a known disposable-provider list, and whether it is a role address like info@ or admin@. Boundstone's email check returns exactly those signals, plus whether the domain is a free provider, and it lists what it checked and what it did not. It does not perform SMTP mailbox probing or catch-all detection, so a clean result confirms the address is well-formed and the domain is set up to receive mail, not that a specific inbox exists.

Does an email showing as 'valid' mean the account behind it is real?

No, and it is worth being precise about this. In Boundstone a valid email means the syntax is correct, the domain publishes an MX record, and it is not on the disposable or role-account lists; it does not prove the mailbox actually exists or can receive mail, because SMTP mailbox and catch-all checks are deliberately not performed and are reported as not_performed on every response. For fraud work, treat valid as worth sending a confirmation email to, not as proof of a real person. Pairing that signal with a genuine double-opt-in confirmation is what actually ties the address to a human.

Can I screen phone numbers and IP addresses at signup too, or just email?

You can screen all three. Boundstone validates phone numbers for format, region, and line-type metadata, and validates IP addresses for format, version, and range classification, so you can flag malformed numbers or source IPs that are private, reserved, or otherwise not publicly routable at the signup door. Each response spells out what it did and did not check: phone does not do carrier lookup, ported status, or HLR liveness by default (they're a paid opt-in via hlr:true), and IP does not do geolocation, ASN, proxy/VPN/Tor, or reputation, so you always know what a result actually proves. All three checks run on the free tier of 250 credits a month with no card, one at a time or in bulk CSV jobs.

Thomas Tsui

Founder of Boundstone — building phone, email and IP validation you can actually verify.

One honest API for email, phone and IP — every response lists what it checked and what it didn't claim to. Free tier: 250 credits/month, no card, credits never expire.

More from Boundstone — API documentation · Benchmark methodology · The benchmark series · Buyer's checklist