Predax Blog

Product updates, best practices, and deep dives into IP intelligence.

Form Spam in 2026: Why Bots Still Get Through reCAPTCHA (and What Actually Works)
Predax Team

Form Spam in 2026: Why Bots Still Get Through reCAPTCHA (and What Actually Works)

form-spamcaptchabot-preventionhoneypotwordpress

The Lead

In the 2023 USENIX Security paper "An Empirical Study & Evaluation of Modern CAPTCHAs" by Searles, Nakatsuka, Ozturk, Paverd, Tsudik, and Enkoji, researchers at UC Irvine and ETH Zürich ran a 1,400-person, 14,000-challenge user study measuring human and bot performance against every major CAPTCHA type then deployed. The headline finding: bots already solve distorted-text CAPTCHAs with near-100% accuracy in under a second, while humans take up to 15 seconds and land between 50% and 84% accuracy. On image-based reCAPTCHA, human solve times (~18 seconds) are indistinguishable from bot solve times (~17.5 seconds). That study is now almost three years old. AI-powered form-fillers have not slowed down since.

If you are a WordPress or WooCommerce operator in 2026 watching your contact form fill with casino spam, affiliate-link payloads, and vaguely-threatening "SEO services" pitches despite reCAPTCHA being enabled: this is why. CAPTCHA-as-sole-defence is an architecture from a decade ago. The modern answer is a small layered stack: honeypots, timing checks, IP reputation, and CAPTCHA as an advisory tie-breaker rather than a gate. Here is how to build it.

TL;DR

  • CAPTCHAs lost the arms race around 2023. Bots now beat reCAPTCHA v2 image challenges at near-100% accuracy in under a second, per the 2023 USENIX paper.
  • CAPTCHA-solving farms charge under $0.003 per solved challenge. Pure-CAPTCHA defence is economically defeated for any attacker running more than a trickle of abuse.
  • Honeypot fields plus timing checks catch most unsophisticated spam for free. Pair them with IP reputation on submission to catch the sophisticated rest.
  • reCAPTCHA v3, Turnstile, and hCaptcha are still useful as *advisory* signals — their scores feed into a risk decision rather than making it alone.

Why reCAPTCHA Is Losing (And Why Google Knows It)

reCAPTCHA v2 — the "click to confirm you are human" checkbox, sometimes escalating to a 3x3 grid of traffic-light photos — was Google's default web-bot filter for nearly a decade. By 2023 it was decisively broken for adversaries who cared to break it. The USENIX Security paper linked above benchmarked modern open-source computer-vision models against reCAPTCHA v2 image challenges and found that bot solve rates rivaled or exceeded human ones, while costing compute time measured in hundreds of milliseconds. Coverage at TechXplore summarised the finding in a single sentence: bots are better at CAPTCHA than humans, and have been for years.

reCAPTCHA v3, Google's successor, tried to fix this by moving to invisible behavioural scoring. Rather than showing a challenge, v3 watches mouse movement, keystroke rhythm, scroll behaviour, and a hundred other micro-signals, then returns a score between 0.0 (almost certainly a bot) and 1.0 (almost certainly human) per request. The official docs recommend a default threshold of 0.5 and urge admins to tune per-action based on observed traffic.

Two problems. First, AI-driven form-fillers that generate human-like mouse traces, plausible typing rhythms, and realistic viewport scroll have gotten cheap. A headless browser driven by a modern puppeteer + residential-proxy stack routinely scores 0.7–0.9 on v3 for prices orders of magnitude below the value of a spam submission. Second, Google itself has pivoted — reCAPTCHA Enterprise is now the officially-recommended tier for any site that cares about accurate risk scoring, and the v3 public docs carry a banner pointing there. The free tier still works, but it is no longer where Google is investing.

The user-experience cost of the CAPTCHA-as-gate posture is not zero either. Accessibility research has consistently shown that audio challenges and visual puzzles disproportionately exclude users with disabilities. The 2023 study notes that image-based challenges impose a cognitive load on *all* users that meaningfully reduces form-completion rates — the classic "we stopped the bots and lost 12% of signups" tradeoff. Running a CAPTCHA because you've always run one, without measuring the conversion cost against the spam it actually catches, is increasingly the wrong call.

The takeaway for operators in 2026: keep a CAPTCHA in the mix if you already have one deployed and integrated, but do not treat its verdict as a yes/no gate. Its score is one signal. The decision belongs to the broader risk model.

The Economics of Spam

The single most useful lens for thinking about form spam is the cost-per-successful-submission from the attacker's side. Spam works only when that number stays below the per-submission economic return (an affiliate click, a stolen-credential placement, a backlink implant, etc.).

CAPTCHA-solving farms publish their prices openly. As of mid-2026, 2Captcha's public pricing quotes reCAPTCHA v2 at roughly £0.80–£2.45 per 1,000 solves, and distorted-image CAPTCHAs at £0.45–£0.89 per 1,000. Anti-Captcha's pricing lists reCAPTCHA v2 at \$0.95–\$2 per 1,000 and reCAPTCHA v3 at roughly \$1–\$2 per 1,000 depending on required score quality. Translating: a motivated attacker pays between \$0.001 and \$0.003 per CAPTCHA solved. These services front-run the actual computer-vision automation with human microworkers for the rare cases the model fails, guaranteeing 99.9%+ solve rates.

At those prices, pure CAPTCHA defence is a losing proposition for any attack whose per-submission return exceeds \$0.003 — which is every attack. Affiliate-spam links routinely return \$0.10–\$10 per successful comment placement. Backlink spam on a medium-authority domain is worth multiples of that. Email-harvesting for later phishing is worth \$0.01–\$0.05 per harvested address. Even the worst-paying attacks clear the CAPTCHA cost by factors of 10–1000x.

This is also why Imperva's Bad Bot Report consistently reports automated traffic as a huge and growing share of web requests — Imperva's 2022 report pegged bad bots at 27.7% of observed online traffic, and that number has not materially improved. The economics favour automation at scale. Your defence has to change the economics by raising per-submission cost on the attacker, which a solved CAPTCHA does not do.

Honeypots, timing checks, and IP reputation raise per-submission cost because each one requires an attacker-side behavioural change (dedicated form analysis, human-like form-filling pacing, acquiring residential-grade proxy traffic) rather than a capability the CAPTCHA farm already sells at commodity prices. That is the underlying mechanism of why these defences work: they are not blocking on a skill, they are blocking on a cost.

Honeypot Fields — Still the Cheapest Effective Defence

A honeypot field is a form input that is invisible to human users but visible in the raw HTML. Automated form submitters — which largely work by parsing the form DOM and filling every input they find — will populate the honeypot field. Human users never see it, so they never fill it. On submit, any request with a non-empty honeypot is silently discarded.

OWASP classifies spam-to-forms as OAT-017 Spamming and CAPTCHA-defeat as OAT-009 in their Automated Threats project. The remediation guidance for OAT-017 explicitly recommends field-based traps as a first line of defence — and the reason they still work after 20 years is the same reason the economics argument works: generic spam bots do not invest engineering effort in per-site form analysis. They parse, they fill, they submit. A well-implemented honeypot catches them.

Implementation matters. A naive display: none honeypot will trigger screen readers, which will read the field label aloud to users with disabilities, who will then fill it out and be falsely rejected. The correct implementation layers four attributes that collectively hide the field from humans *and* assistive tech while keeping it visible to dumb bots:

<div aria-hidden="true" style="position: absolute; left: -9999px;">
  <label for="website_url">Do not fill this out</label>
  <input
    type="text"
    name="website_url"
    id="website_url"
    tabindex="-1"
    autocomplete="off"
    aria-hidden="true"
    value=""
  />
</div>

The aria-hidden="true" attributes remove the field from the accessibility tree per W3C ARIA guidance. The tabindex="-1" keeps keyboard users from ever focusing the field. The autocomplete="off" prevents password managers from auto-populating it. And the off-screen positioning (via position: absolute; left: -9999px) is preferred over display: none because some bots explicitly skip fields with display: none but not ones that are off-screen.

The name you pick matters a little — spam bots more readily fill fields named url, website, email (if you already have a real email field), or phone. A field called xyzzy42 will catch fewer bots than one called website_url. Treat the name as part of the bait.

The Predax WordPress Security plugin ships with honeypot traps on both the login form and (by default) the comment form — so any WordPress site running the plugin picks up login and comment-spam defence without any per-site implementation work. The mechanics are identical to the snippet above; the plugin just handles the rendering and the server-side validation. For contact forms and other non-default locations, you still need to add the honeypot yourself, but the two WordPress-native abuse vectors (login and comments) are covered out of the box.

Timing Analysis — The Bot Tell That Works

The second cheap defence is timing. A human reading a contact form, composing a message, and hitting submit takes between 1.5 seconds (a terse "interested, please contact me") and 15 seconds (a considered description of a problem). A bot parsing the DOM, filling all fields, and submitting typically takes under 500 milliseconds — often under 100. The time-to-submit distribution of genuine humans overlaps almost nothing with the distribution of unsophisticated bots.

The implementation is trivial: record the timestamp when the form renders, record the timestamp when it submits, reject any submission where the elapsed time is below a threshold. Client-side JavaScript is the cleanest place to do it:

(function() {
  var loadedAt = Date.now();
  var form = document.querySelector('form#contact');
  form.addEventListener('submit', function(e) {
    var elapsed = Date.now() - loadedAt;
    if (elapsed < 1500) {
      e.preventDefault();
      console.warn('submission too fast:', elapsed, 'ms');
      return false;
    }
    var hidden = form.querySelector('[name="_form_loaded_at"]');
    if (hidden) hidden.value = String(loadedAt);
  });
})();

Pair this with a server-side check — the form loaded-at timestamp should round-trip through a hidden field so the server can re-validate it against the current time and its own threshold. Bots that never execute the JavaScript fail at the client layer; bots that do execute the JavaScript but pretend the timestamp, fail at the server layer. The threshold of 1,500ms drops essentially all unsophisticated bots while practically never triggering on genuine humans (the 1% of exceptionally fast human responders can tolerate one refresh). For longer forms (job applications, lengthy feedback), raise the threshold to 3,000ms or more.

Timing checks pair naturally with honeypots because the two catch disjoint attacker behaviours. A bot that respects the honeypot but fills instantly still fails timing. A bot that paces submission correctly but fills the honeypot still fails that. Both are free, client-plus-server. Neither costs any user experience for legitimate visitors.

IP Reputation — Filtering by Who's Asking

The third layer moves from "what is the submission shaped like" to "who is sending it." The Imperva data above — bad bots as roughly 27.7% of all automated traffic — tells you what share of inbound submissions are probably unwanted. Most spam does not come from residential eyeballs; it comes from hosting ASNs (DigitalOcean, Hetzner, OVH, Linode) or residential-proxy services repackaging eyeball IPs at scale.

On submission, a single API call to an IP reputation service lets you short-circuit the highest-risk submissions before they touch downstream systems. Using Predax's /api/v1/check/ip endpoint:

import requests, os
from flask import request, abort

def should_accept_submission(ip):
    r = requests.post(
        "https://predax.io/api/v1/check/ip",
        headers={"X-API-Key": os.environ["PREDAX_API_KEY"]},
        json={"ip": ip},
        timeout=2,
    ).json()
    classification = r.get("classification", {})
    location = r.get("location", {})
    # Hard-reject anything with risk >= 80 or from hosting ASNs
    if classification.get("risk_score", 0) >= 80:
        return False
    if classification.get("is_hosting") and location.get("country_code") != "US":
        return False
    return True

@app.route("/contact", methods=["POST"])
def contact_submit():
    ip = request.headers.get("CF-Connecting-IP") or request.remote_addr
    if not should_accept_submission(ip):
        abort(429)  # or silently accept-and-drop
    # ... normal processing ...

The classification.risk_score field (0–100) is the primary input, and a threshold of 70–80 will hard-reject the worst network-layer abusers with few false positives. The classification.is_hosting flag catches bot traffic that does not yet have historical reputation but is originating from DigitalOcean or Hetzner IPs — no residential user composes a contact-form message from a cloud VM. The network.asn and location.country_code fields let you express more nuanced rules (ignore risk for specific allowlisted networks, raise the threshold for markets where you expect abuse).

The same pattern applies to account signup, comment posting, and any other form accepting public input — we covered the adjacent problem of bot-driven fraudulent registrations in our fake-signups playbook. The network-layer signal is the most durable component of a spam defence because it works even when bots correctly handle honeypots, pace their timing, and solve CAPTCHAs. Bots need *some* IP to originate from, and that IP's reputation is the one thing they cannot cheaply change.

Behavioural Signals — What Turnstile and hCaptcha Do Right

CAPTCHAs as visible challenges are a 2010s architecture. The current generation of challenge services does something different: invisible behavioural verification plus hardware-attestation probing.

Cloudflare Turnstile is the clearest example. Turnstile's Managed and Invisible modes show no visible challenge to most visitors. Instead the widget runs proof-of-work puzzles, probes browser APIs for signatures consistent with legitimate browser engines, measures hardware and timing characteristics, and returns a token that the backend validates against Cloudflare's scoring service. Crucially, Turnstile's checks do not require traffic to go through Cloudflare's network at all — you can use it as a pure widget on any host. For most legitimate human users the verification is so fast it's imperceptible; for bots that cannot plausibly emulate real browser hardware characteristics, it silently fails.

hCaptcha's Enterprise offering moved in the same direction. Their siteverify response now carries a score (continuous risk estimate) and score_reason field for Enterprise customers, and their passive and near-passive "No-CAPTCHA" modes operate without showing image grids. The economics differ — hCaptcha originally monetised via paid data-labelling on the image challenges, which made them prefer visible modes — but the product has caught up with the rest of the field.

Both services work well for the "am I looking at a real browser driven by a real human" question. Both are integratable in minutes. A single line of script, a form widget, a server-side verify call, and done.

Where they fail: neither is a silver bullet. Sophisticated attackers run real Chrome browsers under puppeteer or Playwright on residential-proxy IPs and pass all three (Turnstile, hCaptcha, reCAPTCHA v3) at reasonable rates. When that attacker shows up, the network-layer reputation signal is what catches them — and even then, not every attacker has obvious network-layer reputation yet. This is why the stack is a *stack*: no single layer holds, but the combination raises per-submission cost above the attacker's breakeven. For many sites, "Turnstile + honeypot + server-side timing" is the whole defensible story. For sites with stronger spam pressure, add IP reputation as Layer 3 and content analysis as Layer 4.

A Stack That Actually Works in 2026

Here is the recipe, written as a four-layer stack. Each layer is cheap, each layer catches different bots, and each layer composes cleanly with the others.

LayerMechanismCatchesCost
1Honeypot + server-side timing checkGeneric form-filling bots, low-effort scrapersFree (dev time only)
2Turnstile (Managed) or reCAPTCHA v3Headless browsers, basic automation, fake UAsFree tier for most sites
3IP reputation API on submitHosting-ASN traffic, known-bad IPs, residential proxiesLow — typical API plan
4Content analysis (Akismet, OOPSpam)Spam content that got through Layers 1–3Free tier or low-cost API

The decision rule for tiered rejection is straightforward: Layer 1 failure (honeypot filled, timing too fast) is near-certain bot, silently drop the submission — no message, no error, just record it and move on. Layer 2 failure (CAPTCHA score very low) is probable bot, drop silently or surface a soft "please try again" without revealing the score. Layer 3 failure (high risk score plus hosting ASN) is probably spam, drop silently and optionally return a 200 to the bot so it does not learn what triggered rejection. Layer 4 failure (content-analysis confident spam) is discovered after the fact — Akismet reports having blocked over 500 billion spam submissions across 100 million WordPress sites since 2005 at 99.99% stated accuracy, which is the reason it stays in every serious WordPress spam stack.

Silent rejection matters because any visible error signal — "detected spam," "CAPTCHA failed," "invalid submission" — teaches the attacker something about which layer caught them, and they'll adjust. 200 OK with the submission discarded is indistinguishable from success, from the bot's perspective, and it wastes attacker budget continuing to send identical payloads that will never reach a human. That is the right default for unsophisticated spam. For high-volume abuse campaigns, return a 429 with a rate-limit header and let them learn to back off.

How Predax Helps

Every call to Predax's /api/v1/check/ip endpoint returns the four fields you need for Layer-3 form-spam decisions in a single low-latency JSON response: `risk_score` (0–100 composite signal blending Tor, proxy, VPN, datacenter, and community telemetry), `asn` (the origin Autonomous System Number), `is_hosting` (boolean — is this IP on a hosting provider rather than a residential ISP), and `country_code` (for geographic rule layering). A contact form can wire this check in under twenty lines of server code as shown above; the typical roundtrip is 50–250 milliseconds against our production endpoint, small enough to hide inside normal form-processing latency.

For WordPress and WooCommerce operators who don't want to run their own rejection logic, the Predax WordPress Security plugin v1.9.1 wraps the same signals in plugin UI with zero custom code. Out of the box the plugin ships login-form honeypots, a comment-form honeypot on by default, a JavaScript challenge page that unsophisticated bots fail, reCAPTCHA v3 integration as an optional advisory layer, fingerprint scoring on visit traffic, scanner-trap honeypot URLs that catch automated vulnerability scanners, a 404 threshold that auto-blocks aggressive probers, login protection with per-IP rate limits, and bot verification for legitimate crawlers (Googlebot, Bingbot, and others) via forward-confirmed reverse DNS. The dashboard's threat log shows every blocked request with the reason — honeypot tripped, IP risk too high, bot challenge failed, etc. — so you can audit rejections and tune thresholds without black-boxing your own decisions.

None of this replaces a human reviewing edge cases; it gives you the network-layer signal accurately and keeps your forms open to real customers instead of to 2Captcha-as-a-service attackers. View pricing for plan tiers including a generous free plan that covers small-scale production use.

Frequently Asked Questions

Is reCAPTCHA v3 still worth using in 2026?

Yes, but only as one signal in a stack — not as a sole defence. reCAPTCHA v3 returns a 0.0–1.0 score per request, which gives you useful input for a risk decision, and the per-request cost (free for most sites) is low enough to justify keeping it on. But the 2023 USENIX paper on modern CAPTCHA defeat showed bots already match human solving times on reCAPTCHA, and AI form-fillers have gotten better since. The right role in 2026 is as a tie-breaker: honeypot + timing + IP reputation decides most outcomes; reCAPTCHA v3's score disambiguates the ambiguous cases. Don't use it as your only rejection signal.

Do honeypots hurt accessibility?

Only if you implement them carelessly. A honeypot field applied as display: none with no accessibility hints will be read aloud by screen readers and filled in by legitimate disabled users, generating false positives that exclude the most vulnerable visitors. The fix is a three-attribute implementation: aria-hidden="true" to keep the field out of the accessibility tree, tabindex="-1" to keep it off the keyboard-focus order, and autocomplete="off" to keep password managers from auto-filling it. Many implementations also apply visibility: hidden or a label with aria-hidden="true" and sr-only CSS as belt-and-braces. Done correctly, honeypots are invisible to assistive tech and to sighted users — and W3C-ARIA documents the attributes to use.

Will blocking by IP reputation cause false positives?

Some, yes — but far fewer than blocking by country or by CAPTCHA score alone. A well-run IP reputation API returns a continuous risk score rather than a binary label, which lets you route the top band (say, score ≥ 80) to hard rejection, a middle band (40–80) to a step-up challenge, and the bottom band through untouched. False positives overwhelmingly concentrate in two groups: corporate VPN users on hosting ASNs and cellular carrier-grade-NAT IPs shared by many subscribers. Offering an appeal path ("having trouble? email us") covers both groups without eroding the defensive value of the signal. Silent rejection plus no appeal is the failure mode to avoid.

What's the difference between hCaptcha, Turnstile, and reCAPTCHA?

All three are challenge-response bot-filter services; they differ on business model, signals, and default UX. reCAPTCHA v3 is Google's frictionless scorer — runs invisibly, returns 0.0–1.0 per request, free for most traffic volume, with a paid Enterprise tier for higher-volume/lower-false-positive needs. hCaptcha historically emphasized visible image challenges and data-labelling revenue, with an Enterprise risk-score tier that mirrors reCAPTCHA's scoring model. Cloudflare Turnstile is the newer entrant — proof-of-work and browser-quirk probing, no image challenges at all, a Managed mode that adapts per-visitor, and a privacy stance that doesn't require Cloudflare to sit in front of your traffic. Turnstile is the lowest-friction option for most sites; pick whichever you're already integrated with for the others.

Related guides

Run WordPress? The Predax WordPress plugin drops IP reputation into Contact Form 7, WPForms, Gravity, and Elementor in one click. See pricing.