{"record":{"id":"71c1d37e6ff99fcb","repo":"kgretzky/evilginx2","slug":"phishing-urls-and-phishing-parameters-count-do-not","errorCode":null,"errorMessage":"phishing urls and phishing parameters count do not match","messagePattern":"phishing urls and phishing parameters count do not match","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/terminal.go","lineNumber":1667,"sourceCode":"\t\t\t\t\t\t\tt, err := r.Token()\n\t\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\t\treturn ret, ret_params, err\n\t\t\t\t\t\t\t}\n\n\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn ret, ret_params, fmt.Errorf(\"array of parameters not found\")\n\t\t\t}*/\n\t}\n\treturn ret, ret_params, nil\n}\n\nfunc (t *Terminal) exportPhishUrls(export_path string, phish_urls []string, phish_params []map[string]string, format string) error {\n\tif len(phish_urls) != len(phish_params) {\n\t\treturn fmt.Errorf(\"phishing urls and phishing parameters count do not match\")\n\t}\n\tif !stringExists(format, []string{\"text\", \"csv\", \"json\"}) {\n\t\treturn fmt.Errorf(\"export format can only be 'text', 'csv' or 'json'\")\n\t}\n\n\tf, err := os.OpenFile(export_path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer f.Close()\n\n\tif format == \"text\" {\n\t\tfor n, phish_url := range phish_urls {\n\t\t\tvar params string\n\t\t\tm := 0\n\t\t\tparams_row := phish_params[n]\n\t\t\tfor k, v := range params_row {\n\t\t\t\tif m > 0 {","sourceCodeStart":1649,"sourceCodeEnd":1685,"githubUrl":"https://github.com/kgretzky/evilginx2/blob/4c0988a1d9db4d172a185e979a38bfd0efdb5830/core/terminal.go#L1649-L1685","documentation":"exportPhishUrls writes generated phishing URLs together with their per-URL parameter maps, and it refuses to run when the two slices have different lengths. Each URL must correspond 1:1 to a parameters map; a mismatch means the internal pairing was corrupted, so the export aborts to avoid writing misaligned rows.","triggerScenarios":"Programmatically calling exportPhishUrls (or the lure export path in handleLures that feeds it) with len(phish_urls) != len(phish_params), typically after building one slice but not the other or filtering one without the other.","commonSituations":"Custom builds/scripts that append to ret but skip ret_params on an error branch (note importParamsFromFile only appends both together), or manually constructed slices passed to the exported function.","solutions":["Build both slices together in the same loop iteration so they stay index-aligned.","If filtering, filter both slices with the same predicate before calling exportPhishUrls.","Assert len(urls) == len(params) at the call site to fail fast with a clearer message."],"exampleFix":"// before\nurls = append(urls, u)\nif bad { params = append(params, p) }\n// after\nif !bad { urls = append(urls, u); params = append(params, p) }","handlingStrategy":"validation","validationCode":"if len(phishUrls) != len(phishParams) {\n    return fmt.Errorf(\"refusing export: %d urls vs %d param maps\", len(phishUrls), len(phishParams))\n}\nerr := t.exportPhishUrls(path, phishUrls, phishParams, format)","typeGuard":null,"tryCatchPattern":"if err := t.exportPhishUrls(path, urls, params, format); err != nil {\n    if strings.Contains(err.Error(), \"count do not match\") {\n        log.Printf(\"slice alignment bug: %d urls, %d params\", len(urls), len(params))\n        return\n    }\n    return err\n}","preventionTips":["Append to urls and params in the same code block","Filter both slices with one shared predicate","Add a debug assert on equal lengths in any custom import/export code"],"tags":["data-integrity","export","invariants"],"backgroundTag":"mismatched-array-lengths","analyzedSha":"4c0988a1d9db4d172a185e979a38bfd0efdb5830","analyzedAt":"2026-09-05T19:23:07.238Z","contentChangedAt":"2026-09-05T19:23:07.238Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}