Skip to content

"CSRF Verification Failed" error in the Cloudflare Turnstile Captcha Stage with Nginx Proxy Manager + Authentik #4131

@obadaahmar

Description

@obadaahmar

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:
Image

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions