projectdiscovery/nuclei · error

post-auth read: %s (got: %s)

Error message

post-auth read: %s (got: %s)

What it means

The post-authentication read returned an error other than context.DeadlineExceeded. Auth deliberately tolerates a timeout after sending credentials (silence is treated as success), so this error fires only for real I/O failures — connection reset, EOF, or a canceled context — while scanning for FailBanners vs ShellPrompts. Note the message is formatted with %s (preview of bytes received) rather than wrapping the error with %w.

Source

Thrown at pkg/utils/telnetmini/telnet.go:230

	}
	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)
	for _, fb := range c.FailBanners {
		if low == strings.ToLower(fb) {
			return errors.New("authentication failed")
		}
	}
	// success (matched a shell prompt or timed out without explicit failure)
	return nil
}

// Exec sends a command followed by CRLF and returns text captured until one of
// the provided prompts appears (typically your shell prompt). Provide a deadline via ctx.
func (c *Client) Exec(ctx context.Context, command string, until ...string) (string, error) {
	if err := c.writeLine(ctx, command); err != nil {
		return "", err
	}
	_, out, err := c.readUntil(ctx, until...)

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Treat a reset-after-credentials as an authentication failure or target-level defect: verify credentials manually (e.g. with a telnet client) to see whether the socket reset is the server's reject behavior.
  2. Confirm you are speaking plain telnet and not TLS/SSH — a TLS or SSH greeting will never match the configured prompts and can cause an abnormal teardown.
  3. If ctx.Canceled is being produced by your own supervisor, avoid canceling Auth mid-flight or map it to a clean abort path.
  4. Extend the ctx budget so slow post-login banner output is not misread as failure.

Example fix

// before
err := client.Auth(ctx, user, pass)

// after
err := client.Auth(ctx, user, pass)
if err != nil && strings.Contains(err.Error(), "post-auth read") {
    // socket died scanning for fail/shell banners; count as failed auth for this host
    log.Printf("host %s reset after auth: %v", host, err)
}
Defensive patterns

Strategy: try-catch

Type guard

func isPostAuthReadErr(err error) bool {
    return err != nil && strings.HasPrefix(err.Error(), "post-auth read:")
}

Try / catch

err := client.Auth(ctx, user, pass)
if isPostAuthReadErr(err) {
    // transport died scanning fail/shell banners: treat as auth failure for this host
    log.Printf("%s: post-auth drop: %v", host, err)
}

Prevention

When it happens

Trigger: The remote end drops the TCP connection right after credentials are submitted (banner-based auth rejection, service crash, PAM failure without a banner), or ctx is canceled (context.Canceled, not DeadlineExceeded) during the final read.

Common situations: Devices that reset the socket instead of printing a failure banner on bad credentials; aggressive per-attempt ctx cancellation from a scanner supervisor; TLS-wrapped services mistakenly spoken to as plain telnet.

Related errors


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