projectdiscovery/nuclei · error
sending username: %w
Error message
sending username: %w
What it means
Client.Auth's second step: after a login prompt matched, the username plus CRLF is written via writeLine (io.WriteString + Flush) under the ctx deadline. A write or flush error returns 'sending username: %w' — meaning the connection died in the narrow window between receiving the prompt and sending the credential line.
Source
Thrown at pkg/utils/telnetmini/telnet.go:214
i += 2 // Skip command and option
}
}
}
return supportsEncryption, options
}
// Auth performs a minimal Telnet username/password interaction.
// It waits for a username/login prompt, sends username, waits for a password prompt,
// sends password, and then looks for fail banners or shell prompts.
// A timeout should be enforced via ctx.
func (c *Client) Auth(ctx context.Context, username, password string) error {
// Wait for username/login prompt
if _, _, err := c.readUntil(ctx, c.UserPrompts...); err != nil {
return fmt.Errorf("waiting for login/username prompt: %w", err)
}
if err := c.writeLine(ctx, username); err != nil {
return fmt.Errorf("sending username: %w", err)
}
// Wait for password prompt
if _, _, err := c.readUntil(ctx, c.PasswordPrompts...); err != nil {
return fmt.Errorf("waiting for password prompt: %w", err)
}
if err := c.writeLine(ctx, password); err != nil {
return fmt.Errorf("sending password: %w", err)
}
// Post-auth: look quickly for explicit failure, else accept shell prompt / silence.
match, got, err := c.readUntil(ctx,
append(append([]string{}, c.FailBanners...), c.ShellPrompts...)...,
)
if err != nil && !errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("post-auth read: %s (got: %s)", preview(got, 200), err)
}
low := strings.ToLower(match)View on GitHub (pinned to 265b3a3dec)
Solutions
- Retry with backoff — the prompt was seen, so the protocol is right; the drop is usually a transient limit
- Lower concurrency against this target and add a delay between attempts to avoid connection limits
- Check the wrapped error: broken pipe/EPIPE vs i/o timeout vs RST each point to server-side kill vs stall
- Verify the same credentials manually with `telnet target` to confirm the server accepts interactive login at all
Defensive patterns
Strategy: retry
Validate before calling
// Health-check the write path right after the prompt match:
if err := conn.SetWriteDeadline(time.Now().Add(3 * time.Second)); err != nil {
return err
} Try / catch
err := client.Auth(ctx, user, pass)
if err != nil && strings.Contains(err.Error(), "sending username") {
time.Sleep(500 * time.Millisecond)
// reconnect and retry once — prompt was seen, drop is usually a transient limit
return authWithNewConn(ctx, user, pass)
} Prevention
- Expect servers to drop sessions under load — always make telnet auth retryable with a fresh connection
- Cap concurrent auth attempts per host to stay under inetd/fail2ban thresholds
- Use the ctx deadline so a stalled write fails fast instead of hanging the worker
- Log the wrapped syscall error (EPIPE vs timeout) to distinguish server kill from stall
When it happens
Trigger: Server resets the connection right after the banner (inetd per-connection limits, fail2ban matching on the negotiation bytes, TLS-expecting service receiving plaintext), a full send buffer on a stalled connection causing the deadline to expire mid-write, or the ctx deadline expiring exactly after the prompt read.
Common situations: Aggressive parallel telnet scanning tripping hosts.allow/fail2ban that kill the session after the first interaction round; flaky links where reads succeed but writes race a reset; hardcoded credentials tests against appliances that drop connections on unexpected input.
Related errors
- failed to send encryption packet: %w
- waiting for login/username prompt: %w
- sending password: %w
- max sleep count
- authentication failed
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/3b9e91681c3201f5.
Report an issue: GitHub.