{"record":{"id":"11c6652e7206ed12","repo":"projectdiscovery/nuclei","slug":"invalid-number-of-recipients-required-1-got-d","errorCode":null,"errorMessage":"invalid number of recipients: required 1, got %d","messagePattern":"invalid number of recipients: required 1, got (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/libs/smtp/smtp.go","lineNumber":156,"sourceCode":"\t}\n\n\taddr := net.JoinHostPort(c.host, c.port)\n\tconn, err := dialer.Fastdialer.Dial(c.nj.Context(), \"tcp\", addr)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tdefer func() {\n\t\t_ = conn.Close()\n\t}()\n\tclient, err := smtp.NewClient(conn, c.host)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tif err := client.Mail(msg.from); err != nil {\n\t\treturn false, err\n\t}\n\tif len(msg.to) == 0 || len(msg.to) > 1 {\n\t\treturn false, fmt.Errorf(\"invalid number of recipients: required 1, got %d\", len(msg.to))\n\t}\n\tif err := client.Rcpt(msg.to[0]); err != nil {\n\t\treturn false, err\n\t}\n\n\t// Send the email body.\n\twc, err := client.Data()\n\tif err != nil {\n\t\treturn false, err\n\t}\n\n\t_, err = wc.Write([]byte(msg.String()))\n\tif err != nil {\n\t\treturn false, err\n\t}\n\terr = wc.Close()\n\tif err != nil {\n\t\treturn false, err","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/smtp/smtp.go#L138-L174","documentation":"Returned by smtp.Client.IsOpenRelay when the SMTPMessage does not have exactly one recipient: the check rejects len(msg.to) == 0 and len(msg.to) > 1 after the MAIL FROM command. The open-relay probe is intentionally minimal — one sender, one recipient — so the library enforces a single Rcpt call rather than guessing which recipient to test.","triggerScenarios":"Calling IsOpenRelay with a message where To() was never called (zero recipients); adding multiple recipients (To called twice, or an AddTo-style API used repeatedly) before the probe; copying message-building code from a send-email flow that legitimately has several recipients.","commonSituations":"Template authors reusing mail-composition helpers that add default recipients; forgetting the To step entirely; assuming the library loops over recipients like a real MTA submit.","solutions":["Set exactly one recipient on the message before IsOpenRelay","Remove extra To/AddTo calls that inflate the recipient list","If you built a multi-recipient message, construct a fresh single-recipient message for the relay probe"],"exampleFix":"// before\nconst msg = new smtp.SMTPMessage();\nmsg.From('attacker@evil.com');\nmsg.To('a@evil.com');\nmsg.To('b@evil.com');\nclient.IsOpenRelay(msg);\n\n// after\nconst msg = new smtp.SMTPMessage();\nmsg.From('attacker@evil.com');\nmsg.To('a@evil.com');\nclient.IsOpenRelay(msg);","handlingStrategy":"validation","validationCode":"const msg = new smtp.SMTPMessage();\nmsg.From(fromAddr);\nmsg.To(singleRecipient); // exactly one\n// do not call To/AddTo again before IsOpenRelay\nclient.IsOpenRelay(msg);","typeGuard":null,"tryCatchPattern":"try { client.IsOpenRelay(msg) } catch (e) { if (String(e).includes('invalid number of recipients')) { /* rebuild message with one recipient */ } else { throw e; } }","preventionTips":["Build a dedicated single-recipient message for relay probes","Do not reuse multi-recipient compose helpers","Set the recipient immediately after From to avoid omission"],"tags":["smtp","javascript","nuclei","input-validation"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}