kgretzky/evilginx2 · error
sub_filters: missing `search` field
Error message
sub_filters: missing `search` field
What it means
Each `sub_filters` entry needs a `search` regular expression identifying the text to replace in matched responses. The parser found a nil `search` field and aborts validation. Without it the substitution engine has no pattern to act on.
Source
Thrown at core/phishlet.go:451
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 {
(*sf.Mimes)[n] = p.paramVal((*sf.Mimes)[n])
}
p.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)
}
}
if fp.JsInject != nil {
for _, js := range *fp.JsInject {
if js.TriggerDomains == nil {
return fmt.Errorf("js_inject: missing `trigger_domains` field")View on GitHub (pinned to 4c0988a1d9)
Solutions
- Add `search: '<escaped regex>'` (e.g. `search: 'accounts\\.example\\.com'`) to the entry
- Escape regex dots and remember the string is matched against response content, not the URL
- Reload and fix any subsequently reported missing fields (replace comes next)
Example fix
// before
sub_filters:
- triggers_on: 'auth.example.com'
orig_sub: 'accounts'
domain: 'example.com'
mimes: ['text/html']
replace: 'accounts.{domain}'
// after
sub_filters:
- triggers_on: 'auth.example.com'
orig_sub: 'accounts'
domain: 'example.com'
mimes: ['text/html']
search: 'accounts\\.example\\.com'
replace: 'accounts.{domain}' Defensive patterns
Strategy: validation
Validate before calling
import re
for i, sf in enumerate(cfg.get('sub_filters') or []):
pat = sf.get('search')
if pat is None:
raise ValueError(f"sub_filters[{i}]: missing `search` field")
re.compile(pat) Type guard
func validSubFilter(sf SubFilter) bool { return sf.Search != nil } Prevention
- Escape dots in hostnames in the search regex (\\.)
- Write search and replace together so one is never missing
- Test the regex against a sample response body before loading
When it happens
Trigger: A `sub_filters:` entry omits `search:`; core/phishlet.go's `if sf.Search == nil` check fires before p.addSubFilter is called.
Common situations: Writing a filter that only has replace but forgetting search; YAML multiline regex formatting errors that silently dropped the key; schema confusion with js_inject which has no search field.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- sub_filters: missing `domain` field
- sub_filters: missing `mimes` field
- sub_filters: missing `replace` field
- sub_filters: missing `triggers_on` field
- sub_filters: missing `orig_sub` field
AI-assisted analysis of kgretzky/evilginx2@4c0988a1d9 (2026-09-05).
Data as JSON: /api/errors/8aeca9ced1016a14.
Report an issue: GitHub.