From fe7ec671df60ce41597503ef6dd8c6858c713ddf Mon Sep 17 00:00:00 2001 From: Christian Nolte Date: Sun, 24 May 2026 15:18:28 +0200 Subject: [PATCH] fix: guard read_body in captcha verify state for HTTP/2 requests ngx.req.read_body() raises a runtime error for HTTP/2 (and HTTP/3) requests without a Content-Length header. The captcha verify-state handler in csmod.Allow() called read_body unconditionally, causing nginx to return HTTP 500 whenever a client with an active captcha decision reloaded the challenge page over HTTP/2. The guard mirrors the one already used in get_body(): if the protocol is HTTP/2+ and Content-Length is missing, skip the body read and treat the request as having no POST args. Genuine captcha form submissions are POSTs from browsers that always include Content-Length, so the guard does not interfere with the verification flow. Closes #63 --- lib/crowdsec.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/crowdsec.lua b/lib/crowdsec.lua index 7ede3ec..362c95f 100644 --- a/lib/crowdsec.lua +++ b/lib/crowdsec.lua @@ -753,8 +753,18 @@ function csmod.Allow(ip) local source, state_id, err = flag.GetFlags(flags) if previous_uri ~= nil and state_id == flag.VERIFY_STATE then - ngx.req.read_body() - local args, err = ngx.req.get_post_args() + -- HTTP/2 and HTTP/3 requests without Content-Length cause read_body to error. + -- Browsers reloading the captcha page send HTTP/2 GET with no Content-Length, + -- so we skip body-reading in that case and fall through to re-serve the captcha. + -- Genuine captcha form submissions are POSTs with Content-Length set. + local can_read_body = not (ngx.req.http_version() >= 2 and ngx.var.http_content_length == nil) + local args, err + if can_read_body then + ngx.req.read_body() + args, err = ngx.req.get_post_args() + else + args = {} + end if args and not err then local captcha_res = args[csmod.GetCaptchaBackendKey()] or 0