-
Notifications
You must be signed in to change notification settings - Fork 559
Description
I've recentely implemented the captcha remediation phase in CrowdSec as per the latest available documentation from CrowdSec.
This is my current config:
name: captcha_remediation
filters:
- Alert.Remediation == true && Alert.GetScope() == "Ip" && Alert.GetScenario() contains "http"
decisions:
- type: captcha
duration: 4h
notifications:
- discord
- report_abuse_ip_db
on_success: break
---
name: default_ip_remediation
#debug: true
filters:
- Alert.Remediation == true && Alert.GetScope() == "Ip"
decisions:
- type: ban
duration: 72h
notifications:
- discord
- report_abuse_ip_db
#duration_expr: Sprintf('%dh', (GetDecisionsCount(Alert.GetValue()) + 1) * 4)
# notifications:
# - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this.
# - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this.
# - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this.
# - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this.
on_success: break
I've also setup my Nginx Proxy Manager with the OpenResty bouncer setup as following:
ENABLED=true
API_URL=http://XXX.XXX.XXX.XXX:8086
API_KEY=[REDACTED]
CACHE_EXPIRATION=1
# bounce for all type of remediation that the bouncer can receive from the local API
BOUNCING_ON_TYPE=all
FALLBACK_REMEDIATION=ban
REQUEST_TIMEOUT=3000
UPDATE_FREQUENCY=10
# By default internal requests are ignored, such as any path affected by rewrite rule.
# set ENABLE_INTERNAL=true to allow checking on these internal requests.
ENABLE_INTERNAL=false
# live or stream
MODE=live
# exclude the bouncing on those location
EXCLUDE_LOCATION=
#those apply for "ban" action
# /!\ REDIRECT_LOCATION and RET_CODE can't be used together. REDIRECT_LOCATION take priority over RET_CODE
BAN_TEMPLATE_PATH=/config/crowdsec/templates/ban.html
REDIRECT_LOCATION=
RET_CODE=404
#those apply for "captcha" action
#valid providers are recaptcha, hcaptcha, turnstile
CAPTCHA_PROVIDER=turnstile
# Captcha Secret Key
SECRET_KEY=[REDACTED]
# Captcha Site key
SITE_KEY=[REDACTED]
CAPTCHA_TEMPLATE_PATH=/config/crowdsec/templates/captcha.html
CAPTCHA_EXPIRATION=3600
## Application Security Component Configuration
APPSEC_URL=http://XXX.XXX.XXX.XXX:7422
#### default ###
APPSEC_FAILURE_ACTION=passthrough
APPSEC_CONNECT_TIMEOUT=100
APPSEC_SEND_TIMEOUT=100
APPSEC_PROCESS_TIMEOUT=1000
ALWAYS_SEND_TO_APPSEC=false
SSL_VERIFY=true
##############
Which has always worked for the ban type of remediation, however when the user is presented with the Captcha challenge and after it is successfully resolved, we are receiving this type of error:

I've enabled debug mode in the OpenResty bouncer and this was the type of logging I was receiving:
2025/12/07 16:11:39 [debug] 470#470: *154 [lua] crowdsec.lua:466: allowIp(): live mode
2025/12/07 16:11:39 [debug] 470#470: *154 [lua] http.lua:633: send_request():
GET /v1/decisions?ip=2001:8004:d01:b94f:1972:42b0:729f:19c4 HTTP/1.1
x-api-key: [REDACTED]
Connection: close
Host: XXX.XXX.XXX.XXX:8086
User-Agent: crowdsec-openresty-bouncer/v1.1.0
2025/12/07 16:11:39 [debug] 470#470: *154 [lua] live.lua:72: live_query(): [CACHE] Adding 'ipv6_[REDACTED_IPv6_ADDRESS]' in cache for '1' seconds with decision type'captcha'with origin'cscli
2025/12/07 16:11:39 [debug] 470#470: *154 [lua] crowdsec.lua:479: allowIp(): live_query: [REDACTED_IPv6_ADDRESS] | banned with | captcha | cscli | nil
2025/12/07 16:11:39 [debug] 470#470: *154 [lua] crowdsec.lua:291: get_body(): No content-length header in request
2025/12/07 16:11:39 [debug] 470#470: *154 [lua] http.lua:633: send_request():
GET / HTTP/1.1
cf-connecting-ip: [REDACTED_IPv6_ADDRESS]
cf-ipcountry: AU
accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-language: en-AU
accept-encoding: gzip, br
x-crowdsec-appsec-api-key: [REDACTED]
user-agent: Mozilla/5.0 (Android 16; Mobile; rv:145.0) Gecko/145.0 Firefox/145.0
x-forwarded-for: [REDACTED_IPv6_ADDRESS]
sec-fetch-mode: navigate
cookie: authentik_csrf=[REDACTED]; cf_clearance=[REDACTED]; authentik_session=[REDACTED]
sec-fetch-site: none
priority: u=0, i
sec-fetch-user: ?1
cf-ray: [REDACTED]
host: XXX.XXX.XXX.XXX:7422
x-crowdsec-appsec-ip: [REDACTED_IPv6_ADDRESS]
upgrade-insecure-requests: 1
x-crowdsec-appsec-host: auth.domain.tld
cf-visitor: {"scheme":"https"}
x-crowdsec-appsec-verb: GET
x-forwarded-proto: https
x-crowdsec-appsec-uri: /if/user/
sec-fetch-dest: document
x-crowdsec-appsec-user-agent: Mozilla/5.0 (Android 16; Mobile; rv:145.0) Gecko/145.0 Firefox/145.0
cdn-loop: cloudflare; loops=1
Here is the current Nginx Proxy Manager for this example subdomain (auth.domain.tld):
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
Not sure where the issue is happening, is it from CrowdSec config, the OpenResty bouncer, or Authentik itself.
Would appreciate any type of guidance.
/kind bug