valyala/fasthttp · error

proxy dial target address contains cr or lf: %q

Error message

proxy dial target address contains cr or lf: %q

What it means

httpProxyDial validates the target address before building the CONNECT request through an HTTP proxy. Addresses containing CR or LF would enable request-splitting/header injection in the proxy request, so dialing is refused with this error.

Source

Thrown at fasthttpproxy/dialer.go:229

// In the httpProxyDial function, the proxy.Dialer that implements
// this interface can retrieve timeout information when sending the CONNECT
// method to the HTTP proxy.
type httpProxyDialer interface {
	connectTimeout() time.Duration
}

// DialerFunc Make a function of type func(network, addr string) (net.Conn, error)
// implement the proxy.Dialer interface.
type DialerFunc func(network, addr string) (net.Conn, error)

func (d DialerFunc) Dial(network, addr string) (net.Conn, error) {
	return d(network, addr)
}

// Establish a connection through an HTTP proxy.
func httpProxyDial(dialer proxy.Dialer, network, addr, proxyAddr, auth string) (net.Conn, error) {
	if strings.ContainsAny(addr, "\r\n") {
		return nil, fmt.Errorf("proxy dial target address contains cr or lf: %q", addr)
	}

	conn, err := dialer.Dial(network, proxyAddr)
	if err != nil {
		return nil, err
	}
	var connectTimeout time.Duration
	hp, ok := dialer.(httpProxyDialer)
	if ok {
		connectTimeout = hp.connectTimeout()
	}

	if connectTimeout > 0 {
		if err = conn.SetDeadline(time.Now().Add(connectTimeout)); err != nil {
			_ = conn.Close()
			return nil, err
		}
		defer func() {

View on GitHub (pinned to c96f600972)

Solutions

  1. Sanitize the target host: strip/reject any control characters before dialing
  2. Parse the URL with net/url and use only u.Host, which normalizes out CR/LF
  3. Reject the request at the application layer with a 400-style response when the host contains \r or \n
  4. Log the rejected address for security monitoring

Example fix

// before
dialer.Dial("tcp", rawHostFromUser) // rawHostFromUser = "evil.com:80\r\nX: y"
// after
u, err := url.Parse("http://" + rawHostFromUser)
if err != nil || strings.ContainsAny(u.Host, "\r\n") {
    return fmt.Errorf("invalid proxy target host: %q", rawHostFromUser)
}
dialer.Dial("tcp", u.Host)
Defensive patterns

Strategy: validation

Validate before calling

if strings.ContainsAny(targetAddr, "\r\n") {
    return errors.New("target address must not contain CR or LF")
}

Type guard

func isSafeProxyTarget(addr string) bool {
    u, err := url.Parse("http://" + addr)
    return err == nil && u.Host == addr && !strings.ContainsAny(addr, "\r\n\x00")
}

Try / catch

conn, err := proxyDialer.Dial("tcp", addr)
if err != nil {
    if strings.Contains(err.Error(), "contains cr or lf") {
        return fmt.Errorf("rejected unsafe proxy target: %q", addr)
    }
    return err
}

Prevention

When it happens

Trigger: Calling (&fasthttpproxy.HttpProxyDialer{...}).Dial (or ProxyDialer) with an addr like "example.com:80\r\nX-Evil: 1", typically from unsanitized user input or a malicious URL host.

Common situations: Proxying URLs built from raw user input, CRLF injection attempts from untrusted clients, Host headers copied verbatim from inbound requests.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/66886df85df75aa0. Report an issue: GitHub.