Skip to content

appsec: return 403, not 200, when the failure action is deny - #159

Closed
mangyan1 wants to merge 1 commit into
crowdsecurity:mainfrom
mangyan1:fix-appsec-failure-status-code
Closed

mangyan1 wants to merge 1 commit into
crowdsecurity:mainfrom
mangyan1:fix-appsec-failure-status-code

Conversation

@mangyan1

Copy link
Copy Markdown

Problem

With APPSEC_FAILURE_ACTION=deny, a failing AppSec call (engine down, timeout, DNS failure) blocks the request — but serves the ban response with HTTP 200:

local ok, remediation, status_code = true, "allow", 200
if runtime.conf["APPSEC_FAILURE_ACTION"] == DENY then
  ok = false
  remediation = runtime.conf["FALLBACK_REMEDIATION"]
end
...
if err ~= nil then
  ...
  return ok, remediation, status_code, {}, err   -- status_code is still the 200 placeholder
end

In Allow(), the appsecOk == false path passes that status_code to ban.apply(ret_code), so during an AppSec outage clients get the ban page body with a 200 status. Monitoring that alerts on status codes sees a healthy service while every request is actually being denied.

Verified against a live setup (AppSec engine stopped with APPSEC_FAILURE_ACTION=deny + FALLBACK_REMEDIATION=ban): requests return the ban page with HTTP/1.1 200 OK, and the log shows [Crowdsec] denied '<ip>' with 'ban' (by appsec).

Fix

Set status_code = ngx.HTTP_FORBIDDEN in the deny branch. A successful query overrides it on every live path (res.status == 200 allows, the 403 branch assigns response.http_status or ngx.HTTP_FORBIDDEN), so the change only affects the failure return. With passthrough the error path keeps ok = true and Allow() ignores the value, so passthrough behavior is unchanged.

This also matches the existing unreadable-body drop path, which already returns ngx.HTTP_FORBIDDEN directly.

🤖 Generated with Claude Code

@mangyan1 mangyan1 closed this by deleting the head repository Sep 17, 2026
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