kgretzky/evilginx2 · error
proxy_hosts: missing `phish_sub` field
Error message
proxy_hosts: missing `phish_sub` field
What it means
Thrown while iterating over the `proxy_hosts` list during validation when an entry is missing the `phish_sub` field. `phish_sub` defines the subdomain shown to the victim on the attacker's phishing domain (e.g. `login` in login.example.phishing). Every proxy_host entry must contain it so the proxy can route requests.
Source
Thrown at core/phishlet.go:398
if fp.AuthTokens == nil {
return fmt.Errorf("missing `auth_tokens` section")
}
if fp.Credentials == nil {
return fmt.Errorf("missing `credentials` section")
}
if fp.Credentials.Username == nil {
return fmt.Errorf("credentials: missing `username` section")
}
if fp.Credentials.Password == nil {
return fmt.Errorf("credentials: missing `password` section")
}
if fp.LoginItem == nil {
return fmt.Errorf("missing `login` section")
}
for _, ph := range *fp.ProxyHosts {
if ph.PhishSub == nil {
return fmt.Errorf("proxy_hosts: missing `phish_sub` field")
}
if ph.OrigSub == nil {
return fmt.Errorf("proxy_hosts: missing `orig_sub` field")
}
if ph.Domain == nil {
return fmt.Errorf("proxy_hosts: missing `domain` field")
}
auto_filter := true
if ph.AutoFilter != nil {
auto_filter = *ph.AutoFilter
}
p.addProxyHost(p.paramVal(*ph.PhishSub), p.paramVal(*ph.OrigSub), p.paramVal(*ph.Domain), ph.Session, ph.IsLanding, auto_filter)
}
if len(p.proxyHosts) == 0 {
return fmt.Errorf("proxy_hosts: list cannot be empty")
}
session_set := false
for _, ph := range p.proxyHosts {View on GitHub (pinned to 4c0988a1d9)
Solutions
- Add `phish_sub:` to every entry under `proxy_hosts:`
- Set it to the subdomain of the original host that entry proxies (e.g. `login`, `www`, `mail`)
- Use `''` if the host has no subdomain (empty value still counts as present)
Example fix
// before
proxy_hosts:
- orig_sub: login
domain: example.com
// after
proxy_hosts:
- phish_sub: login
orig_sub: login
domain: example.com Defensive patterns
Strategy: validation
Validate before calling
type proxyHost struct {
PhishSub *string `yaml:"phish_sub"`
OrigSub *string `yaml:"orig_sub"`
Domain *string `yaml:"domain"`
}
var fp struct { ProxyHosts *[]proxyHost `yaml:"proxy_hosts"` }
yaml.Unmarshal(data, &fp)
for i, ph := range *fp.ProxyHosts {
if ph.PhishSub == nil {
return fmt.Errorf("proxy_hosts[%d]: missing phish_sub", i)
}
} Type guard
func validProxyHosts(phs []ProxyHost) bool {
for _, ph := range phs {
if ph.PhishSub == nil || ph.OrigSub == nil || ph.Domain == nil {
return false
}
}
return len(phs) > 0
} Try / catch
err := cfg.AddPhishlet("local", name)
if err != nil {
if strings.Contains(err.Error(), "missing `phish_sub` field") {
log.Fatalf("phishlet %s: each proxy_hosts entry needs phish_sub/orig_sub/domain", name)
}
return err
} Prevention
- Give every proxy_hosts entry all three keys: phish_sub, orig_sub, domain
- Use '' explicitly for entries with no subdomain
- Keep keys hyphenated exactly: phish_sub not phish-sub
- Lint the YAML before loading
When it happens
Trigger: A `proxy_hosts:` entry in the phishlet YAML defines `orig_sub` and/or `domain` but omits `phish_sub`, or the key is misspelled/mis-indented so the struct field stays nil.
Common situations: Hand-editing entries and deleting a line; typos like `phish-sub` or `phishsub`; copying an entry where phish_sub was removed intentionally but the entry left in place.
Related errors
- proxy_hosts: missing `orig_sub` field
- proxy_hosts: missing `domain` field
- proxy_hosts: list cannot be empty
- missing `credentials` section
- credentials: missing `username` section
AI-assisted analysis of kgretzky/evilginx2@4c0988a1d9 (2026-09-05).
Data as JSON: /api/errors/8395c596f690f9f7.
Report an issue: GitHub.