{"record":{"id":"a8135cbb0ee5bc2a","repo":"kgretzky/evilginx2","slug":"sub-filters-missing-domain-field","errorCode":null,"errorMessage":"sub_filters: missing `domain` field","messagePattern":"sub_filters: missing `domain` field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/phishlet.go","lineNumber":445,"sourceCode":"\t\tif ph.is_landing {\n\t\t\tlanding_set = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !landing_set {\n\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)","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/kgretzky/evilginx2/blob/4c0988a1d9db4d172a185e979a38bfd0efdb5830/core/phishlet.go#L427-L463","documentation":"Each `sub_filters` entry requires a `domain`, the registrable domain whose subdomain strings are rewritten. The parser found a nil `domain` field and refuses to register the filter. This is the base domain used when substituting `orig_sub.domain` with the phishing host.","triggerScenarios":"A `sub_filters:` list item in the phishlet YAML omits `domain:`; core/phishlet.go's nil check `if sf.Domain == nil` fires during validation.","commonSituations":"Copying a filter block and deleting the domain line; assuming domain is inherited from `triggers_on`; YAML indentation mistake that dropped the key into a sibling map.","solutions":["Add `domain: <registrable-domain>` (e.g. `domain: 'example.com'`) to the sub_filters entry","Confirm the value is the registrable base domain without the subdomain prefix","Check YAML indentation so `domain:` belongs to the same list item as `triggers_on` and `orig_sub`","Reload and continue fixing any subsequent reported fields"],"exampleFix":"// before\nsub_filters:\n  - triggers_on: 'auth.example.com'\n    orig_sub: 'accounts'\n    mimes: ['text/html']\n// after\nsub_filters:\n  - triggers_on: 'auth.example.com'\n    orig_sub: 'accounts'\n    domain: 'example.com'\n    mimes: ['text/html']","handlingStrategy":"validation","validationCode":"for i, sf in enumerate(cfg.get('sub_filters') or []):\n    if sf.get('domain') is None:\n        raise ValueError(f\"sub_filters[{i}]: missing `domain` field\")","typeGuard":"func validSubFilter(sf SubFilter) bool { return sf.Domain != nil }","tryCatchPattern":null,"preventionTips":["Always include the registrable base domain, distinct from triggers_on","Check that domain belongs to the same YAML list item (indentation)","Keep sub_filters entries grouped with host/domain commented for clarity"],"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"}