CAPTCHA

Overview

The CAPTCHA system supports three providers, selectable globally. Challenge actions are available for WAF rules, Security Rules, and rate limits. When a challenge is triggered, the client is redirected to a challenge page, and upon successful completion, a cookie is issued that bypasses future challenges for a configurable TTL.

Providers

Native (cap)

The built-in proof-of-work service. This is the default provider and requires no external service or API keys. The challenge is self-hosted and served by coreX Manager.

reCAPTCHA

Google reCAPTCHA v2 or v3 (with configurable score threshold). Requires a site key and secret from Google.

Turnstile

A CAPTCHA widget from an external provider. Requires a site key and secret.

Third-party providers

reCAPTCHA is a Google service and Turnstile is a service from another company. Both require their own site keys and secrets. The Native provider is self-hosted by coreX Manager and requires no external service.

Challenge Action

The challenge action is available for:

  • WAF rules — challenge requests that exceed the anomaly threshold
  • Security Rules — challenge requests matching a rule expression
  • Rate limits — challenge clients that exceed the rate limit

When triggered, the challenge action:

  1. Checks for a valid _cv cookie
  2. If valid, allows the request through
  3. If invalid, emits a redirect to the challenge page with rule context
  4. The challenge page presents the CAPTCHA
  5. On success, sets the _cv cookie and redirects back to the original URL

Client Binding

The _cv token is bound to the client via a hash of:

  • Client IP
  • User-Agent
  • JA4 TLS fingerprint

This means a leaked cookie cannot be replayed from a different client.

Why JA4 binding?

Binding to the JA4 fingerprint adds another layer of client identity beyond IP and User-Agent. Even if an attacker steals the cookie and spoofs the IP and User-Agent, a different TLS client will have a different JA4 fingerprint and fail the binding check.

Request ID

HAProxy’s unique-id is passed through the challenge pipeline for correlation with access logs and WAF metrics. This lets you trace a challenge event back to the original request.

Global TTL

captcha_valid_seconds (default 3600 = 1 hour) controls how long the _cv cookie is valid. Configurable from the CAPTCHA page UI.

Challenge Event Tracking

The system logs three event types per rule:

  • Issued — a challenge was presented
  • Solved — the challenge was completed successfully
  • Failed — the challenge was attempted but failed

Each event includes the request_id for correlation.

Settings Page

The CAPTCHA settings page has three tabs:

Provider Tab

  • Provider selector (Native / reCAPTCHA / Turnstile)
  • Per-provider configuration fields:
    • Native: no configuration needed
    • reCAPTCHA: site key, secret, version (v2/v3), score threshold (v3)
    • Turnstile: site key, secret

Stats Tab

  • Per-rule solve rate
  • Recent challenge events (issued, solved, failed)

Keys Tab (Native provider only)

  • Cap admin API proxy for managing Native provider keys

Step-by-Step: Configure the Native Provider

  1. Navigate to Security > CAPTCHA
  2. In the Provider tab, select Native
  3. Set the TTL (default 3600 is fine)
  4. Click Save
  5. No keys or external configuration needed — the Native provider is ready to use

Step-by-Step: Configure reCAPTCHA

  1. Obtain a site key and secret from Google reCAPTCHA
  2. Navigate to Security > CAPTCHA
  3. Select reCAPTCHA as the provider
  4. Enter the site key and secret
  5. Select version (v2 or v3)
  6. If v3, set the score threshold (e.g. 0.5)
  7. Click Save

Step-by-Step: Create a Challenge Rule

  1. Navigate to Security > Security Rules

  2. Click Add Rule

  3. Name: challenge-suspicious

  4. Expression: risk.score > 50

  5. Action: challenge

  6. Save and Apply

  7. Test:

    curl -k https://localhost/

    A request that triggers the rule should redirect to the challenge page.

Verification

  1. Trigger a challenge:

    curl -k -v https://localhost/ 2>&1 | grep -i 'location\|set-cookie'

    Expect a redirect to the challenge page and no _cv cookie on the first request.

  2. Complete the challenge and verify the _cv cookie is set.

  3. Re-request with the cookie:

    curl -k -b "_cv=<token>" https://localhost/

    The request should pass through without a challenge.

  4. Check stats:

    • Navigate to Security > CAPTCHA > Stats
    • Verify issued, solved, and failed events appear

Next Steps

  • Security Rules — Create rules that trigger challenges
  • WAF — Use challenge actions in WAF rules
  • Rate Limiting — Challenge clients that exceed limits