{"record":{"id":"8aeca9ced1016a14","repo":"kgretzky/evilginx2","slug":"sub-filters-missing-search-field","errorCode":null,"errorMessage":"sub_filters: missing `search` field","messagePattern":"sub_filters: missing `search` field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/phishlet.go","lineNumber":451,"sourceCode":"\t\tp.proxyHosts[0].is_landing = true\n\t}\n\n\tif fp.SubFilters != nil {\n\t\tfor _, sf := range *fp.SubFilters {\n\t\t\tif sf.Hostname == nil {\n\t\t\t\treturn fmt.Errorf(\"sub_filters: missing `triggers_on` field\")\n\t\t\t}\n\t\t\tif sf.Sub == nil {\n\t\t\t\treturn fmt.Errorf(\"sub_filters: missing `orig_sub` field\")\n\t\t\t}\n\t\t\tif sf.Domain == nil {\n\t\t\t\treturn fmt.Errorf(\"sub_filters: missing `domain` field\")\n\t\t\t}\n\t\t\tif sf.Mimes == nil {\n\t\t\t\treturn fmt.Errorf(\"sub_filters: missing `mimes` field\")\n\t\t\t}\n\t\t\tif sf.Search == nil {\n\t\t\t\treturn fmt.Errorf(\"sub_filters: missing `search` field\")\n\t\t\t}\n\t\t\tif sf.Replace == nil {\n\t\t\t\treturn fmt.Errorf(\"sub_filters: missing `replace` field\")\n\t\t\t}\n\t\t\tif sf.WithParams == nil {\n\t\t\t\tsf.WithParams = &[]string{}\n\t\t\t}\n\n\t\t\tfor n := range *sf.Mimes {\n\t\t\t\t(*sf.Mimes)[n] = p.paramVal((*sf.Mimes)[n])\n\t\t\t}\n\t\t\tp.addSubFilter(p.paramVal(*sf.Hostname), p.paramVal(*sf.Sub), p.paramVal(*sf.Domain), *sf.Mimes, p.paramVal(*sf.Search), p.paramVal(*sf.Replace), sf.RedirectOnly, *sf.WithParams)\n\t\t}\n\t}\n\tif fp.JsInject != nil {\n\t\tfor _, js := range *fp.JsInject {\n\t\t\tif js.TriggerDomains == nil {\n\t\t\t\treturn fmt.Errorf(\"js_inject: missing `trigger_domains` field\")","sourceCodeStart":433,"sourceCodeEnd":469,"githubUrl":"https://github.com/kgretzky/evilginx2/blob/4c0988a1d9db4d172a185e979a38bfd0efdb5830/core/phishlet.go#L433-L469","documentation":"Each `sub_filters` entry needs a `search` regular expression identifying the text to replace in matched responses. The parser found a nil `search` field and aborts validation. Without it the substitution engine has no pattern to act on.","triggerScenarios":"A `sub_filters:` entry omits `search:`; core/phishlet.go's `if sf.Search == nil` check fires before p.addSubFilter is called.","commonSituations":"Writing a filter that only has replace but forgetting search; YAML multiline regex formatting errors that silently dropped the key; schema confusion with js_inject which has no search field.","solutions":["Add `search: '<escaped regex>'` (e.g. `search: 'accounts\\\\.example\\\\.com'`) to the entry","Escape regex dots and remember the string is matched against response content, not the URL","Reload and fix any subsequently reported missing fields (replace comes next)"],"exampleFix":"// before\nsub_filters:\n  - triggers_on: 'auth.example.com'\n    orig_sub: 'accounts'\n    domain: 'example.com'\n    mimes: ['text/html']\n    replace: 'accounts.{domain}'\n// after\nsub_filters:\n  - triggers_on: 'auth.example.com'\n    orig_sub: 'accounts'\n    domain: 'example.com'\n    mimes: ['text/html']\n    search: 'accounts\\\\.example\\\\.com'\n    replace: 'accounts.{domain}'","handlingStrategy":"validation","validationCode":"import re\nfor i, sf in enumerate(cfg.get('sub_filters') or []):\n    pat = sf.get('search')\n    if pat is None:\n        raise ValueError(f\"sub_filters[{i}]: missing `search` field\")\n    re.compile(pat)","typeGuard":"func validSubFilter(sf SubFilter) bool { return sf.Search != nil }","tryCatchPattern":null,"preventionTips":["Escape dots in hostnames in the search regex (\\\\.)","Write search and replace together so one is never missing","Test the regex against a sample response body before loading"],"tags":["phishlet","config-validation","sub-filters","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"4c0988a1d9db4d172a185e979a38bfd0efdb5830","analyzedAt":"2026-09-05T19:23:07.238Z","contentChangedAt":"2026-09-05T19:23:07.238Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}