waf: the header limits are the first check (closes #311)
check / check (push) Successful in 3m40s

A request over 50 cookies or 100 header fields is now refused by the first
check after SWW_ALLOW_NETS. It causes no lookup, no query to RouteWatch, a DNS
blocklist or AbuseIPDB, no rule file match and no Core Rule Set. The rate
limits no longer count it, and a banned or denied client gets 431 for it. It
makes no ban, makes no ban permanent and is not counted in a ban's notes. In
observe mode no lookup is made for it. Requests within the limits go through
the same checks in the same order.

Model: opus-5-5
This commit is contained in:
sneak committed 2026-11-11 05:13:54 +00:00
1 parent 9bcbe5a3c8
commit aea5392afd
6 files changed
+190 -79

No files matched your search

+4 -6
View File
@@ -143,10 +143,9 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// refusedWhateverTheAnswer reports whether the request is one that does not wait
// for GeoJS, since the checks will refuse it at now whatever GeoJS answers about
// its client: the heuristic crowdsec, header_limits, blocklists or rate_limits
// will refuse it, as a function in that heuristic's file says. In observe mode,
// which refuses nothing, none is. rproxy lets a request through when
// waf answers too late.
// its client: the heuristic crowdsec, blocklists or rate_limits will refuse it,
// as a function in that heuristic's file says. In observe mode, which refuses
// nothing, none is. rproxy lets a request through when waf answers too late.
func (rq *request) refusedWhateverTheAnswer(now time.Time) bool {
if rq.h.config.Observe {
return false
@@ -154,8 +153,7 @@ func (rq *request) refusedWhateverTheAnswer(now time.Time) bool {
_, decided := rq.crowdSecDecisionInForce(now)
return decided || overHeaderLimits(rq.headerCounts()) ||
rq.refusedByBlocklists(rq.h.lists.ListedBy(rq.client)) ||
return decided || rq.refusedByBlocklists(rq.h.lists.ListedBy(rq.client)) ||
rq.overAWholeRateLimit(now)
}