{"record":{"id":"08445d5e069fe21a","repo":"trufflesecurity/trufflehog","slug":"s-is-not-a-valid-regex-error-received-v-08445d","errorCode":null,"errorMessage":"%s is not a valid regex, error received: %v","messagePattern":"(.+?) is not a valid regex, error received: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/detectors/postgres/postgres.go","lineNumber":83,"sourceCode":"\nfunc New(opts ...func(*Scanner)) *Scanner {\n\tscanner := &Scanner{\n\t\tignorePatterns: []*regexp.Regexp{},\n\t}\n\tfor _, opt := range opts {\n\t\topt(scanner)\n\t}\n\n\treturn scanner\n}\n\nfunc WithIgnorePattern(ignoreStrings []string) func(*Scanner) {\n\treturn func(s *Scanner) {\n\t\tvar ignorePatterns []*regexp.Regexp\n\t\tfor _, ignoreString := range ignoreStrings {\n\t\t\tignorePattern, err := regexp.Compile(ignoreString)\n\t\t\tif err != nil {\n\t\t\t\tpanic(fmt.Sprintf(\"%s is not a valid regex, error received: %v\", ignoreString, err))\n\t\t\t}\n\t\t\tignorePatterns = append(ignorePatterns, ignorePattern)\n\t\t}\n\n\t\ts.ignorePatterns = ignorePatterns\n\t}\n}\n\nvar _ detectors.Detector = (*Scanner)(nil)\nvar _ detectors.CustomFalsePositiveChecker = (*Scanner)(nil)\n\nfunc (s Scanner) Keywords() []string {\n\treturn []string{\"postgres\"}\n}\n\nfunc (s Scanner) FromData(ctx context.Context, verify bool, data []byte) ([]detectors.Result, error) {\n\tvar results []detectors.Result\n\tcandidateURIs := findUriMatches(data, s.ignorePatterns)","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/trufflesecurity/trufflehog/blob/bcfcf73aaf4759d4dadc2783177c245a02792318/pkg/detectors/postgres/postgres.go#L65-L101","documentation":"TruffleHog's Postgres detector accepts WithIgnorePattern to suppress false-positive postgres:// connection URIs. Unlike stdlib regexp, this file imports regexp from github.com/wasilibs/go-re2, a WASM build of Google's RE2 engine, so the accepted syntax is strictly RE2: no lookaheads, no lookbehinds, no backreferences, no \\C. Any string go-re2 cannot compile makes the option panic with this message while New(...) applies it, crashing the process at scanner construction. The panic text contains the offending pattern and the compile error, which is all you need to fix it.","triggerScenarios":"Calling postgres.New(postgres.WithIgnorePattern([]string{...})) with a pattern that is invalid under RE2: PCRE-isms like '(?=.*staging)', '(?!dev)', '(?<=user)', or backreferences like '\\1', or plain syntax errors such as unbalanced parentheses, a dangling '\\', or invalid repetition. Note that the same pattern may work fine in other tools (grep -P, ripgrep --pcre2, some config linters) and still panic here because go-re2 rejects the construct outright.","commonSituations":"Copying ignore patterns written for PCRE engines out of other scanners or regex cheat sheets; sourcing patterns from CI environment variables or YAML/JSON config that is never compile-checked before the run; escaping drift when the pattern passes through two layers (YAML single-quote plus Go string); a version where the detector moved from stdlib regexp to go-re2, suddenly rejecting previously accepted lookaround patterns.","solutions":["Read the panic message: it shows the exact pattern and the RE2 error; fix or remove that pattern.","Remove PCRE-only constructs: rewrite '(?=.*staging)' style lookaheads as plain '.*staging', drop lookbehinds and backreferences (repeat the literal group instead).","Keep patterns in raw string literals (backticks) to avoid double-escaping: `postgres://.*\\.staging` not \"postgres://.*\\\\.staging\".","Compile-check every pattern with github.com/wasilibs/go-re2 (the same engine the detector uses) before calling New(), and return an error at the config layer rather than panicking at scan startup.","If patterns arrive untrusted, guard New() with defer/recover and surface the panic as an error."],"exampleFix":"// before\ns := postgres.New(postgres.WithIgnorePattern([]string{\"postgres://(?=.*staging).*\"})) // panics: go-re2 has no lookahead\n\n// after\ns := postgres.New(postgres.WithIgnorePattern([]string{`postgres://.*staging`}))","handlingStrategy":"validation","validationCode":"import (\n\t\"fmt\"\n\tregexp \"github.com/wasilibs/go-re2\"\n)\n\n// Run BEFORE postgres.New(postgres.WithIgnorePattern(...)). Uses\n// go-re2, the exact engine this detector compiles with, so RE2-only\n// rejections (lookahead, backreferences) are caught here, not in a panic.\nfunc validateIgnorePatterns(patterns []string) error {\n\tfor _, p := range patterns {\n\t\tif _, err := regexp.Compile(p); err != nil {\n\t\t\treturn fmt.Errorf(\"invalid postgres ignore pattern %q: %w\", p, err)\n\t\t}\n\t}\n\treturn nil\n}\n\nif err := validateIgnorePatterns(cfg.PostgresIgnorePatterns); err != nil {\n\treturn err // reject config before constructing the scanner\n}","typeGuard":"// True when the string compiles under go-re2 (RE2), the engine the\n// postgres detector uses. PCRE-only patterns return false.\nfunc isValidRE2Pattern(pattern string) bool {\n\t_, err := regexp.Compile(pattern)\n\treturn err == nil\n}","tryCatchPattern":"// Last-resort conversion of the constructor panic into an error.\nfunc newPostgresScanner(opts ...func(*postgres.Scanner)) (sc *postgres.Scanner, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = fmt.Errorf(\"postgres scanner construction failed: %v\", r)\n\t\t}\n\t}()\n\treturn postgres.New(opts...), nil\n}","preventionTips":["Validate patterns with github.com/wasilibs/go-re2 (not stdlib regexp and not an online PCRE tester) so the check matches the engine that panics.","Assume RE2: rewrite '(?=x)' as '.*x', drop lookbehinds and backreferences before shipping a pattern.","Validate at the config boundary (CLI/env/YAML parsing) so users get a clear error instead of a panic mid-startup.","Keep the pattern list in one place with a compile test in CI, mirroring TestPostgres_FromDataWithIgnorePattern.","Use raw string literals (backticks) and remember patterns passing through YAML/JSON add their own escaping layer."],"tags":["go","regex","re2","panic","configuration","trufflehog","postgres","lookahead"],"backgroundTag":null,"analyzedSha":"bcfcf73aaf4759d4dadc2783177c245a02792318","analyzedAt":"2026-08-15T22:39:44.547Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}