{"record":{"id":"0efcc81151dea668","repo":"XTLS/Xray-core","slug":"buffer-overrun","errorCode":null,"errorMessage":"buffer overrun","messagePattern":"buffer overrun","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/socks/protocol.go","lineNumber":302,"sourceCode":"\treturn username, password, nil\n}\n\n// ReadUntilNull reads content from given reader, until a null (0x00) byte.\nfunc ReadUntilNull(reader io.Reader) (string, error) {\n\tb := buf.StackNew()\n\tdefer b.Release()\n\n\tfor {\n\t\t_, err := b.ReadFullFrom(reader, 1)\n\t\tif err != nil {\n\t\t\treturn \"\", err\n\t\t}\n\t\tif b.Byte(b.Len()-1) == 0x00 {\n\t\t\tb.Resize(0, b.Len()-1)\n\t\t\treturn b.String(), nil\n\t\t}\n\t\tif b.IsFull() {\n\t\t\treturn \"\", errors.New(\"buffer overrun\")\n\t\t}\n\t}\n}\n\nfunc hasAuthMethod(expectedAuth byte, authCandidates []byte) bool {\n\tfor _, a := range authCandidates {\n\t\tif a == expectedAuth {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc writeSocks5AuthenticationResponse(writer io.Writer, version byte, auth byte) error {\n\treturn buf.WriteAllBytes(writer, []byte{version, auth}, nil)\n}\n\nfunc writeSocks5Response(writer io.Writer, errCode byte, address net.Address, port net.Port) error {","sourceCodeStart":284,"sourceCodeEnd":320,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/socks/protocol.go#L284-L320","documentation":"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.","triggerScenarios":"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.","commonSituations":"Malicious or fuzzed input probing the SOCKS port; broken 4a implementations that omit the terminator; unusually long machine names/userids.","solutions":["Fix the client to null-terminate userid and domain and keep them short (a domain is max 253 chars anyway).","Treat occurrences from unknown sources as hostile probing: restrict inbound exposure and keep Xray updated.","No server config change affects this; it is purely input-shape validation."],"exampleFix":"// before: userid without terminator, never null\nconn.Write([]byte{0x04, 0x01, 0x00, 0x50, 93, 184, 216, 34, 'r','o','o','t'})\n\n// after: null-terminated userid\nconn.Write([]byte{0x04, 0x01, 0x00, 0x50, 93, 184, 216, 34, 'r','o','o','t', 0x00})","handlingStrategy":"validation","validationCode":"// Client-side: validate strings are short and null-free before encoding\nfunc nullTerm(s string, max int) ([]byte, error) {\n    if len(s) >= max || strings.IndexByte(s, 0) >= 0 {\n        return nil, fmt.Errorf(\"string too long or contains NUL\")\n    }\n    return append([]byte(s), 0x00), nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"buffer overrun\") {\n    conn.Close() // hostile or broken input; drop the session\n    return nil\n}","preventionTips":["Always null-terminate SOCKS4 userid and 4a domain strings.","Keep domains within DNS limits (253 chars).","Rate-limit and restrict exposure of public SOCKS ports to reduce fuzzing noise."],"tags":["socks","protocol","buffer-overrun","input-validation","xray"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}