From afb13e2c5b84077730645d41a28d8cf639cdda62 Mon Sep 17 00:00:00 2001 From: shubhamrasal Date: Wed, 24 Sep 2025 23:16:40 +0530 Subject: [PATCH] Fix panic in DetectWaf function --- pkg/output/stats/waf/waf.go | 44 +++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/pkg/output/stats/waf/waf.go b/pkg/output/stats/waf/waf.go index 7abe68cab..54781460c 100644 --- a/pkg/output/stats/waf/waf.go +++ b/pkg/output/stats/waf/waf.go @@ -5,11 +5,15 @@ import ( "encoding/json" "log" "regexp" + "runtime" + "strings" + "sync" ) type WafDetector struct { wafs map[string]waf regexCache map[string]*regexp.Regexp + mu sync.RWMutex } // waf represents a web application firewall definition @@ -53,19 +57,55 @@ func NewWafDetector() *WafDetector { } func (d *WafDetector) DetectWAF(content string) (string, bool) { - if d == nil || d.regexCache == nil { + if d == nil || d.regexCache == nil || len(content) == 0 { return "", false } + d.mu.RLock() + defer d.mu.RUnlock() + + // Limit content size to prevent regex catastrophic backtracking + maxContentSize := 50000 // 50KB limit + if len(content) > maxContentSize { + content = content[:maxContentSize] + } + for id, regex := range d.regexCache { - if regex != nil && regex.MatchString(content) { + if regex == nil { + continue + } + + // Safely test each regex with panic recovery + matched := func() bool { + defer func() { + if r := recover(); r != nil { + // Get stack trace and format in one line + buf := make([]byte, 4096) + n := runtime.Stack(buf, false) + stack := strings.ReplaceAll(string(buf[:n]), "\n", " | ") + + log.Printf("regex panic for WAF %s: %v: %v", id, r, stack) + } + }() + return regex.MatchString(content) + }() + + if matched { return id, true } } + return "", false } func (d *WafDetector) GetWAF(id string) (waf, bool) { + if d == nil { + return waf{}, false + } + + d.mu.RLock() + defer d.mu.RUnlock() + waf, ok := d.wafs[id] return waf, ok }