XTLS/Xray-core · error

buffer overrun

Error message

buffer overrun

What it means

Thrown by ReadUntilNull (proxy/socks/protocol.go:302) when reading a null-terminated string (SOCKS4 userid or 4a domain) exhausts the buffer without ever seeing 0x00. The function reads byte-by-byte into a fixed-size buf; a string longer than the buffer, or a client that never terminates, hits the IsFull() check and errors.

Source

Thrown at proxy/socks/protocol.go:302

	return username, password, nil
}

// ReadUntilNull reads content from given reader, until a null (0x00) byte.
func ReadUntilNull(reader io.Reader) (string, error) {
	b := buf.StackNew()
	defer b.Release()

	for {
		_, err := b.ReadFullFrom(reader, 1)
		if err != nil {
			return "", err
		}
		if b.Byte(b.Len()-1) == 0x00 {
			b.Resize(0, b.Len()-1)
			return b.String(), nil
		}
		if b.IsFull() {
			return "", errors.New("buffer overrun")
		}
	}
}

func hasAuthMethod(expectedAuth byte, authCandidates []byte) bool {
	for _, a := range authCandidates {
		if a == expectedAuth {
			return true
		}
	}
	return false
}

func writeSocks5AuthenticationResponse(writer io.Writer, version byte, auth byte) error {
	return buf.WriteAllBytes(writer, []byte{version, auth}, nil)
}

func writeSocks5Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Fix the client to null-terminate userid and domain and keep them short (a domain is max 253 chars anyway).
  2. Treat occurrences from unknown sources as hostile probing: restrict inbound exposure and keep Xray updated.
  3. No server config change affects this; it is purely input-shape validation.

Example fix

// before: userid without terminator, never null
conn.Write([]byte{0x04, 0x01, 0x00, 0x50, 93, 184, 216, 34, 'r','o','o','t'})

// after: null-terminated userid
conn.Write([]byte{0x04, 0x01, 0x00, 0x50, 93, 184, 216, 34, 'r','o','o','t', 0x00})
Defensive patterns

Strategy: validation

Validate before calling

// Client-side: validate strings are short and null-free before encoding
func nullTerm(s string, max int) ([]byte, error) {
    if len(s) >= max || strings.IndexByte(s, 0) >= 0 {
        return nil, fmt.Errorf("string too long or contains NUL")
    }
    return append([]byte(s), 0x00), nil
}

Try / catch

if err != nil && strings.Contains(err.Error(), "buffer overrun") {
    conn.Close() // hostile or broken input; drop the session
    return nil
}

Prevention

When it happens

Trigger: A SOCKS4 userid or SOCKS4a domain name longer than the buffer size (2KB buf); a client that sends the string without the trailing 0x00; hostile fuzzing input designed to overrun fixed-size parsing buffers.

Common situations: Malicious or fuzzed input probing the SOCKS port; broken 4a implementations that omit the terminator; unusually long machine names/userids.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/0efcc81151dea668. Report an issue: GitHub.