kgretzky/evilginx2 · error

proxy_hosts: missing `orig_sub` field

Error message

proxy_hosts: missing `orig_sub` field

What it means

Thrown during proxy_hosts validation when an entry lacks the `orig_sub` field. `orig_sub` names the subdomain on the real target site that this host proxies (e.g. `login` for login.example.com), letting the reverse proxy map phishing URLs to legitimate backend hosts. Missing it makes routing ambiguous and the entry is rejected.

Source

Thrown at core/phishlet.go:401

	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 {
		if ph.handle_session {
			session_set = true
			break

View on GitHub (pinned to 4c0988a1d9)

Solutions

  1. Add `orig_sub:` to each proxy_hosts entry
  2. Match it to the real subdomain on the target (e.g. login.example.com -> `login`)
  3. Use `''` when the target host itself has no subdomain

Example fix

// before
proxy_hosts:
  - phish_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.OrigSub == nil {
		return fmt.Errorf("proxy_hosts[%d]: missing orig_sub", i)
	}
}

Type guard

func hasOrigSub(ph ProxyHost) bool {
	return ph.OrigSub != nil
}

Try / catch

err := cfg.AddPhishlet("local", name)
if err != nil {
	if strings.Contains(err.Error(), "missing `orig_sub` field") {
		log.Fatalf("phishlet %s: set orig_sub to the target site's real subdomain", name)
	}
	return err
}

Prevention

When it happens

Trigger: A `proxy_hosts:` entry with `phish_sub` and `domain` but no `orig_sub`, or `orig_sub` misspelled/mis-indented so the YAML key does not bind to ph.OrigSub.

Common situations: Forgetting orig_sub when mirroring an entry; typo `orign_sub`; indentation placing orig_sub as a child of another key.

Related errors


AI-assisted analysis of kgretzky/evilginx2@4c0988a1d9 (2026-09-05). Data as JSON: /api/errors/6b5937209b69996b. Report an issue: GitHub.