Skip to content

Comments

PoC: add provider Cap.js#137

Draft
bmalynovytch wants to merge 1 commit intocrowdsecurity:mainfrom
bmalynovytch:feature/add-provider-Cap.js
Draft

PoC: add provider Cap.js#137
bmalynovytch wants to merge 1 commit intocrowdsecurity:mainfrom
bmalynovytch:feature/add-provider-Cap.js

Conversation

@bmalynovytch
Copy link

@bmalynovytch bmalynovytch commented Feb 13, 2026

Summary

Adds Cap as a fourth supported captcha provider
(CAPTCHA_PROVIDER=cap), alongside the existing recaptcha, hcaptcha and
turnstile.

Cap is a self-hosted, privacy-friendly proof-of-work captcha:

  • No third-party service — validation is done against your own Cap server
  • No tracking, no fingerprinting, no cookies
  • GDPR/ePrivacy friendly
  • Free and open-source (MIT)

Files changed

File Change
lib/plugins/crowdsec/captcha.lua Add cap to the three lookup tables; add ValidateCap() (JSON POST instead of form-encoded); dispatch in Validate(); accept two new optional params in New()
lib/crowdsec.lua Pass CAPTCHA_VERIFY_URL and CAPTCHA_JS_URL to captcha.New()one line changed
config_example.conf Document the two new optional keys

crowdsec.lua already passes CAPTCHA_PROVIDER to captcha.New(), so the
provider dispatch required no structural changes there.

New configuration keys

Only read when CAPTCHA_PROVIDER=cap. Existing configurations are unaffected.

CAPTCHA_PROVIDER=cap
SITE_KEY=<your-cap-site-key>
SECRET_KEY=<your-cap-secret-key>

# URL of your Cap server's validation endpoint
# Default: http://localhost:3000/api/validate
CAPTCHA_VERIFY_URL=http://cap:3000/api/validate

# URL from which browsers load the Cap widget JS
# Default: http://localhost:3000/cap.js
CAPTCHA_JS_URL=http://cap:3000/cap.js

How Cap validation differs from the other providers

The three existing providers (recaptcha, hcaptcha, turnstile) all use the same
protocol: a form-encoded POST to a third-party HTTPS endpoint that returns
{"success": true/false}.

Cap uses a JSON POST to a self-hosted endpoint. The new ValidateCap()
function handles this; the existing Validate() path is unchanged.

Browser                  Nginx bouncer              Cap server (self-hosted)
  │  POST cap-response=… │                           │
  │──────────────────────>│                           │
  │                       │  POST /api/validate       │
  │                       │  { token, secret }  JSON  │
  │                       │──────────────────────────>│
  │                       │  { "success": true }      │
  │                       │<──────────────────────────│
  │  302 → original URI   │                           │
  │<──────────────────────│                           │

Template

The existing captcha.html template is already rendered with
captcha_frontend_js, captcha_frontend_key and captcha_site_key
placeholders. For Cap, those resolve to:

Placeholder Value
captcha_frontend_js value of CAPTCHA_JS_URL
captcha_frontend_key cap
captcha_site_key value of SITE_KEY

A minimal working template snippet for Cap:

<script src="[[captcha_frontend_js]]"></script>
<[[captcha_frontend_key]]-widget data-cap-key="[[captcha_site_key]]"></[[captcha_frontend_key]]-widget>
<input type="hidden" name="[[captcha_frontend_key]]-response" id="cap-response">
<script>
  document.addEventListener('cap:success', function(e) {
    document.getElementById('cap-response').value = e.detail.token;
  });
</script>

Checklist

  • No breaking changes — existing providers are untouched
  • Default values keep backward compatibility (crowdsec.lua passes nil for the new params if keys are absent from config)
  • GetCaptchaBackendKey() returns cap-response for the Cap provider, consistent with the form field name
  • config_example.conf comment updated (#valid providers are recaptcha, hcaptcha, turnstile, cap)

@bmalynovytch bmalynovytch force-pushed the feature/add-provider-Cap.js branch from f5ea3a6 to 8acc811 Compare February 13, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant