{"record":{"id":"1a6e50678e60c2ca","repo":"kgretzky/evilginx2","slug":"credentials-missing-custom-key-field","errorCode":null,"errorMessage":"credentials: missing custom `key` field","messagePattern":"credentials: missing custom `key` field","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/phishlet.go","lineNumber":673,"sourceCode":"\t\t}\n\t}\n\tif !login_domain_ok {\n\t\treturn fmt.Errorf(\"login: `domain` must contain a value of one of the hostnames (`orig_subdomain` + `domain`) defined in `proxy_hosts` section\")\n\t}\n\n\tp.login.path = p.paramVal(*fp.LoginItem.Path)\n\tif p.login.path == \"\" {\n\t\tp.login.path = \"/\"\n\t}\n\tif p.login.path[0] != '/' {\n\t\tp.login.path = \"/\" + p.login.path\n\t}\n\n\tif fp.Credentials.Custom != nil {\n\t\tfor _, cp := range *fp.Credentials.Custom {\n\t\t\tvar err error\n\t\t\tif cp.Key == nil {\n\t\t\t\treturn fmt.Errorf(\"credentials: missing custom `key` field\")\n\t\t\t}\n\t\t\tif cp.Search == nil {\n\t\t\t\treturn fmt.Errorf(\"credentials: missing custom `search` field\")\n\t\t\t}\n\t\t\to := PostField{}\n\t\t\to.key, err = regexp.Compile(p.paramVal(*cp.Key))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"credentials: %v\", err)\n\t\t\t}\n\t\t\to.search, err = regexp.Compile(p.paramVal(*cp.Search))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\to.tp = cp.Type\n\t\t\tif o.tp == \"\" {\n\t\t\t\to.tp = \"post\"\n\t\t\t}\n\t\t\to.key_s = p.paramVal(*cp.Key)","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/kgretzky/evilginx2/blob/4c0988a1d9db4d172a185e979a38bfd0efdb5830/core/phishlet.go#L655-L691","documentation":"Entries in the `credentials.custom` list are used to capture extra POST fields; each entry must specify a `key` (regex matching the POST field name). When a custom entry lacks `key` (nil), phishlet loading aborts with this message.","triggerScenarios":"A phishlet YAML with `credentials: custom: [...]` where one list item has only `search`/`type` and no `key:` field, or a mis-indented item causing its `key` to land on a different mapping.","commonSituations":"Adding custom capture fields by hand and forgetting the key; YAML indentation shifting keys between sibling entries so one item loses its `key`; copying a partial example snippet.","solutions":["Add a `key:` regex to every entry under `credentials.custom`, e.g. `key: '^(csrf|otp)$'`.","Check YAML indentation so each list item is a mapping containing key, search, and optionally type.","Remove empty placeholder items (e.g. a bare `-` dash) from the custom list.","Reload the phishlet and fix any subsequent custom-field errors."],"exampleFix":"// before\ncustom:\n  - search: '[csrf=\"([^\"]+)\"'\n// after\ncustom:\n  - key: 'csrf'\n    search: '[csrf=\"([^\"]+)\"']","handlingStrategy":"validation","validationCode":"for i, c := range pl.Credentials.Custom {\n    if c.Key == nil || c.Search == nil {\n        return fmt.Errorf(\"credentials.custom[%d] needs both key and search\", i)\n    }\n}","typeGuard":"func customFieldComplete(c *CustomField) bool { return c != nil && c.Key != nil && *c.Key != \"\" && c.Search != nil && *c.Search != \"\" }","tryCatchPattern":"if err := pl.Load(cfg); err != nil {\n    if strings.Contains(err.Error(), \"missing custom `key`\") {\n        log.Printf(\"every credentials.custom entry in %s needs a key regex\", pl.Name)\n    }\n}","preventionTips":["Give every custom entry both key and search at the same indentation level.","Validate with a YAML schema requiring key+search per custom item.","Delete empty placeholder list items.","Check indentation after pasting list entries."],"tags":["configuration","phishlet","yaml","missing-field"],"backgroundTag":"missing-required-argument","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"}