kgretzky/evilginx2 · error

sub_filters: missing `orig_sub` field

Error message

sub_filters: missing `orig_sub` field

What it means

Thrown when a `sub_filters` entry passes the hostname (triggers_on) check but lacks the `orig_sub` field. `orig_sub` is the subdomain of the target site whose responses should be searched and rewritten; combined with domain it selects which upstream responses the filter applies to. Missing it leaves the filter untargetable, so validation fails.

Source

Thrown at core/phishlet.go:442

	}
	landing_set := false
	for _, ph := range p.proxyHosts {
		if ph.is_landing {
			landing_set = true
			break
		}
	}
	if !landing_set {
		p.proxyHosts[0].is_landing = true
	}

	if fp.SubFilters != nil {
		for _, sf := range *fp.SubFilters {
			if sf.Hostname == nil {
				return fmt.Errorf("sub_filters: missing `triggers_on` field")
			}
			if sf.Sub == nil {
				return fmt.Errorf("sub_filters: missing `orig_sub` field")
			}
			if sf.Domain == nil {
				return fmt.Errorf("sub_filters: missing `domain` field")
			}
			if sf.Mimes == nil {
				return fmt.Errorf("sub_filters: missing `mimes` field")
			}
			if sf.Search == nil {
				return fmt.Errorf("sub_filters: missing `search` field")
			}
			if sf.Replace == nil {
				return fmt.Errorf("sub_filters: missing `replace` field")
			}
			if sf.WithParams == nil {
				sf.WithParams = &[]string{}
			}

			for n := range *sf.Mimes {

View on GitHub (pinned to 4c0988a1d9)

Solutions

  1. Add `orig_sub:` to each sub_filters entry
  2. Set it to the subdomain on the target that the filter should apply to (use `''` for the bare domain)
  3. Verify all six fields (triggers_on, orig_sub, domain, search, replace, and optional mimes) are siblings under the same list item

Example fix

// before
sub_filters:
  - triggers_on: 'accounts.example.com'
    domain: example.com
    search: 'href="logout"'
    replace: '#'
// after
sub_filters:
  - triggers_on: 'accounts.example.com'
    orig_sub: accounts
    domain: example.com
    search: 'href="logout"'
    replace: '#'
Defensive patterns

Strategy: validation

Validate before calling

type subFilter struct {
	Hostname *string `yaml:"triggers_on"`
	Sub      *string `yaml:"orig_sub"`
	Domain   *string `yaml:"domain"`
}
var fp struct { SubFilters *[]subFilter `yaml:"sub_filters"` }
yaml.Unmarshal(data, &fp)
for i, sf := range *fp.SubFilters {
	if sf.Sub == nil {
		return fmt.Errorf("sub_filters[%d]: missing orig_sub", i)
	}
}

Type guard

func hasOrigSub(sf SubFilter) bool {
	return sf.Sub != nil
}

Try / catch

err := cfg.AddPhishlet("local", name)
if err != nil {
	if strings.Contains(err.Error(), "sub_filters: missing `orig_sub`") {
		log.Fatalf("phishlet %s: each sub_filters entry needs orig_sub to target the upstream subdomain", name)
	}
	return err
}

Prevention

When it happens

Trigger: A sub_filters entry defines `triggers_on`, `domain`, `search`, `replace` but omits `orig_sub:` (or it is misspelled/mis-indented so sf.Sub stays nil).

Common situations: Writing filters with only search/replace pairs copied from CSS-selector style tools; typo `orig-domain`; deleted line while trimming unneeded filters.

Related errors


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