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

  1. Retry with backoff — the prompt was seen, so the protocol is right; the drop is usually a transient limit
  2. Lower concurrency against this target and add a delay between attempts to avoid connection limits
  3. Check the wrapped error: broken pipe/EPIPE vs i/o timeout vs RST each point to server-side kill vs stall
  4. 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

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


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/3b9e91681c3201f5. Report an issue: GitHub.