{"record":{"id":"33289649eb39e954","repo":"kgretzky/evilginx2","slug":"proxy-hosts-list-cannot-be-empty","errorCode":null,"errorMessage":"proxy_hosts: list cannot be empty","messagePattern":"proxy_hosts: list cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/phishlet.go","lineNumber":413,"sourceCode":"\n\tfor _, ph := range *fp.ProxyHosts {\n\t\tif ph.PhishSub == nil {\n\t\t\treturn fmt.Errorf(\"proxy_hosts: missing `phish_sub` field\")\n\t\t}\n\t\tif ph.OrigSub == nil {\n\t\t\treturn fmt.Errorf(\"proxy_hosts: missing `orig_sub` field\")\n\t\t}\n\t\tif ph.Domain == nil {\n\t\t\treturn fmt.Errorf(\"proxy_hosts: missing `domain` field\")\n\t\t}\n\t\tauto_filter := true\n\t\tif ph.AutoFilter != nil {\n\t\t\tauto_filter = *ph.AutoFilter\n\t\t}\n\t\tp.addProxyHost(p.paramVal(*ph.PhishSub), p.paramVal(*ph.OrigSub), p.paramVal(*ph.Domain), ph.Session, ph.IsLanding, auto_filter)\n\t}\n\tif len(p.proxyHosts) == 0 {\n\t\treturn fmt.Errorf(\"proxy_hosts: list cannot be empty\")\n\t}\n\tsession_set := false\n\tfor _, ph := range p.proxyHosts {\n\t\tif ph.handle_session {\n\t\t\tsession_set = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !session_set {\n\t\tp.proxyHosts[0].handle_session = true\n\t}\n\tlanding_set := false\n\tfor _, ph := range p.proxyHosts {\n\t\tif ph.is_landing {\n\t\t\tlanding_set = true\n\t\t\tbreak\n\t\t}\n\t}","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/kgretzky/evilginx2/blob/4c0988a1d9db4d172a185e979a38bfd0efdb5830/core/phishlet.go#L395-L431","documentation":"After parsing all proxy_hosts entries, the validator checks len(p.proxyHosts) == 0 and rejects the phishlet if nothing was added. This happens when the `proxy_hosts` section is present but contains no valid entries (empty list, null items, or every entry failing earlier checks that were skipped). A phishlet with no proxied hosts has nothing to serve and is unusable.","triggerScenarios":"YAML like `proxy_hosts: []` or `proxy_hosts:` with no entries; entries that fail to bind (e.g. wrong types) leaving p.proxyHosts empty after the loop.","commonSituations":"Commenting out all entries during testing and forgetting to restore them; a list whose items are indented wrongly so nothing deserializes; truncation during copy-paste.","solutions":["Ensure `proxy_hosts:` contains at least one complete entry with phish_sub, orig_sub, and domain","Un-comment or restore entries removed during testing","Validate the YAML structure with a parser to confirm the list actually binds"],"exampleFix":"# before\nproxy_hosts: []\n# after\nproxy_hosts:\n  - phish_sub: www\n    orig_sub: www\n    domain: example.com\nlogin:\n  domain: www.example.com\n  path: /login","handlingStrategy":"validation","validationCode":"var fp struct { ProxyHosts *[]ProxyHost `yaml:\"proxy_hosts\"` }\nyaml.Unmarshal(data, &fp)\nif fp.ProxyHosts == nil || len(*fp.ProxyHosts) == 0 {\n\treturn errors.New(\"proxy_hosts must contain at least one entry\")\n}","typeGuard":"func hasProxyHosts(fp *PhishletConfig) bool {\n\treturn fp != nil && fp.ProxyHosts != nil && len(*fp.ProxyHosts) > 0\n}","tryCatchPattern":"err := cfg.AddPhishlet(\"local\", name)\nif err != nil {\n\tif strings.Contains(err.Error(), \"list cannot be empty\") {\n\t\tlog.Fatalf(\"phishlet %s: proxy_hosts needs at least one complete entry\", name)\n\t}\n\treturn err\n}","preventionTips":["Never ship a phishlet with all proxy_hosts entries commented out","Confirm the list has at least one fully-specified entry before loading","Check that list items use `- ` at the correct indentation level","Test-load the phishlet after every edit session"],"tags":["phishlet","proxy-hosts","config-validation"],"backgroundTag":"phishlet-schema-validation","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"}