{"record":{"id":"abd28d0da23578c8","repo":"kgretzky/evilginx2","slug":"missing-login-section","errorCode":null,"errorMessage":"missing `login` section","messagePattern":"missing `login` section","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/phishlet.go","lineNumber":393,"sourceCode":"\t}\n\n\tif fp.ProxyHosts == nil {\n\t\treturn fmt.Errorf(\"missing `proxy_hosts` section\")\n\t}\n\tif fp.AuthTokens == nil {\n\t\treturn fmt.Errorf(\"missing `auth_tokens` section\")\n\t}\n\tif fp.Credentials == nil {\n\t\treturn fmt.Errorf(\"missing `credentials` section\")\n\t}\n\tif fp.Credentials.Username == nil {\n\t\treturn fmt.Errorf(\"credentials: missing `username` section\")\n\t}\n\tif fp.Credentials.Password == nil {\n\t\treturn fmt.Errorf(\"credentials: missing `password` section\")\n\t}\n\tif fp.LoginItem == nil {\n\t\treturn fmt.Errorf(\"missing `login` section\")\n\t}\n\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}","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/kgretzky/evilginx2/blob/4c0988a1d9db4d172a185e979a38bfd0efdb5830/core/phishlet.go#L375-L411","documentation":"Thrown when the phishlet defines credentials but lacks the required top-level `login` section (fp.LoginItem is nil). The `login` section specifies the login URL path and domain on the target site, which Evilginx uses to redirect victims to the real login page and detect successful authentication.","triggerScenarios":"Loading a phishlet YAML that includes proxy_hosts and credentials but omits the `login:` block, or has it mis-indented so it does not bind to the struct.","commonSituations":"Trimming a phishlet down and removing the login block by mistake; renaming `login` to something like `signin`; YAML anchor/tag errors that leave the field nil.","solutions":["Add a top-level `login:` section to the phishlet YAML","Include `domain:` and `path:` fields pointing at the site's real login endpoint","Reload the phishlet after the edit"],"exampleFix":"// before\ncredentials:\n  username:\n    key: username\n  password:\n    key: password\n// after\ncredentials:\n  username:\n    key: username\n  password:\n    key: password\nlogin:\n  domain: accounts.example.com\n  path: /login","handlingStrategy":"validation","validationCode":"var fp struct {\n\tLoginItem *struct {\n\t\tDomain *string `yaml:\"domain\"`\n\t\tPath   *string `yaml:\"path\"`\n\t} `yaml:\"login\"`\n}\nyaml.Unmarshal(data, &fp)\nif fp.LoginItem == nil {\n\treturn errors.New(\"phishlet must define a top-level `login:` section with domain and path\")\n}","typeGuard":"func hasLogin(fp *PhishletConfig) bool {\n\treturn fp != nil && fp.LoginItem != nil\n}","tryCatchPattern":"err := cfg.AddPhishlet(\"local\", name)\nif err != nil {\n\tif strings.Contains(err.Error(), \"missing `login` section\") {\n\t\tlog.Fatalf(\"phishlet %s: add a login block with domain and path\", name)\n\t}\n\treturn err\n}","preventionTips":["Include login.domain and login.path in every phishlet from the start","Point login at the real site's login endpoint, not the phishing domain","Keep `login:` at top-level indentation, not nested under another key","Re-load the phishlet after each structural edit"],"tags":["phishlet","config-validation","login-url"],"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"}