diff --git a/services/security/code_scanner.go b/services/security/code_scanner.go index 61788173fe..633fcb0a24 100644 --- a/services/security/code_scanner.go +++ b/services/security/code_scanner.go @@ -160,7 +160,7 @@ var DefaultCodeRules = []CodeRule{ { ID: "deserialize-yaml-py", Title: "Insecure Deserialization: yaml.load() (Python)", Severity: security_model.SeverityHigh, CWE: "CWE-502", - Pattern: regexp.MustCompile(`yaml\.load\s*\([^)]*(?:Loader\s*=\s*yaml\.(?:Unsafe|Full)Loader|[^)]*\)(?!\s*#))`), + Pattern: regexp.MustCompile(`(?i)yaml\.load\s*\(`), Description: "yaml.load() without SafeLoader allows arbitrary code execution — use yaml.safe_load()", Languages: []string{".py"}, }, diff --git a/services/security/code_scanner_test.go b/services/security/code_scanner_test.go new file mode 100644 index 0000000000..55c6a2c124 --- /dev/null +++ b/services/security/code_scanner_test.go @@ -0,0 +1,23 @@ +// Copyright (C) 2026 Moko Consulting +// SPDX-License-Identifier: GPL-3.0-or-later + +package security + +import "testing" + +// TestDefaultCodeRulesCompile forces the package init, which builds every scanner +// rule's regexp via regexp.MustCompile, and asserts each pattern is present. Go's +// regexp engine is RE2 and rejects Perl-only constructs (lookahead/lookbehind/ +// backreferences) by panicking in MustCompile at init — which crash-loops the +// server at startup. This test executes that init so such a pattern fails CI here +// instead of on a live deploy. +func TestDefaultCodeRulesCompile(t *testing.T) { + if len(DefaultCodeRules) == 0 { + t.Fatal("DefaultCodeRules is empty") + } + for _, r := range DefaultCodeRules { + if r.Pattern == nil { + t.Errorf("rule %q has a nil Pattern", r.ID) + } + } +}