Integrity requirements
Description
VLESS + TCP + REALITY + Vision fails when using www.microsoft.com:443 as REALITY dest / serverNames on Xray-core v26.3.27.
This is not a direct TLS rejection by Microsoft: direct openssl s_client and curl from the same server to www.microsoft.com:443 succeed. The failure appears to be caused by the REALITY server-side target handshake parser rejecting a Microsoft TLS Certificate record whose length is slightly larger than the hardcoded 8192 byte limit in github.com/xtls/reality.
In this environment, Microsoft returns a TLS Certificate record length that leads REALITY to log Certificate: 8273, which is larger than size = 8192, and then the REALITY connection is rejected with handshake did not complete successfully.
Environment
- Xray-core:
Xray 26.3.27 (Xray, Penetrates Everything.) d2758a0 (go1.26.1 linux/amd64)
- OS: Linux x86_64
- Protocol: VLESS + TCP + REALITY +
xtls-rprx-vision
- REALITY dest/serverName:
www.microsoft.com:443 / www.microsoft.com
- Client REALITY fingerprint:
chrome
Sanitized server config shape
Client uses matching VLESS REALITY settings with:
security=reality
sni=www.microsoft.com
fp=chrome
flow=xtls-rprx-vision
type=tcp
Reproduction
- Start Xray server with REALITY
dest: "www.microsoft.com:443", serverNames: ["www.microsoft.com"], show: true.
- Use a matching Xray client on the same host or from another host.
- Send a request through the client, for example:
curl --socks5-hostname 127.0.0.1:<local-socks-port> https://www.google.com/generate_204
Observed client-side result:
curl: (35) Recv failure: Connection reset by peer
HTTP=000 ERR=Recv failure: Connection reset by peer
REALITY debug log
Relevant sanitized server-side REALITY logs:
REALITY remoteAddr: 127.0.0.1:<port>
REALITY remoteAddr: 127.0.0.1:<port> hs.c.ClientVer: [26 3 27]
REALITY remoteAddr: 127.0.0.1:<port> hs.c.ClientTime: 2026-06-21 ... UTC
REALITY remoteAddr: 127.0.0.1:<port> hs.c.ClientShortId: [<redacted>]
REALITY remoteAddr: 127.0.0.1:<port> hs.c.conn == conn: true
REALITY remoteAddr: 127.0.0.1:<port> len(s2cSaved): 5524 Server Hello: 127
REALITY remoteAddr: 127.0.0.1:<port> len(s2cSaved): 5397 Change Cipher Spec: 6
REALITY remoteAddr: 127.0.0.1:<port> len(s2cSaved): 5391 Encrypted Extensions: 51
REALITY remoteAddr: 127.0.0.1:<port> len(s2cSaved): 5340 Certificate: 8273
REALITY remoteAddr: 127.0.0.1:<port> hs.c.isHandshakeComplete.Load(): false
transport/internet/tcp: REALITY: processed invalid connection from 127.0.0.1:<port>: handshake did not complete successfully
Direct TLS to Microsoft succeeds
From the same server, direct TLS to Microsoft succeeds:
openssl s_client -connect www.microsoft.com:443 -servername www.microsoft.com -tls1_3 -brief </dev/null
Output excerpt:
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: C = US, ST = WA, L = Redmond, O = Microsoft Corporation, CN = www.microsoft.com
Verification: OK
DONE
curl https://www.microsoft.com/ also returns HTTP 200 from the same server.
Microsoft Certificate record size
With openssl -msg, Microsoft returns a Certificate record that can exceed the REALITY hardcoded size limit when OCSP/status is involved:
openssl s_client -connect www.microsoft.com:443 -servername www.microsoft.com -tls1_3 -status -msg </dev/null
Relevant output:
<<< TLS 1.2, RecordHeader [length 0005]
17 03 03 20 4c
<<< TLS 1.3, Handshake [length 203b], Certificate
0x204c + 5 = 8273, matching the REALITY debug log line:
Suspected root cause
In github.com/xtls/reality tls.go, the current code appears to have a hardcoded 8192 byte limit:
var (
size = 8192
...
)
...
handshakeLen = recordHeaderLen + Value(s2cSaved[3:5]...)
...
if handshakeLen > size { // too long
break f
}
For this Microsoft target, REALITY computes:
handshakeLen = 8273
size = 8192
8273 > 8192
So the target TLS handshake is rejected as too long, and the connection fails with:
handshake did not complete successfully
Control test
Using the same UUID/key/flow/shortId/client, changing only the REALITY target to another site succeeds. For example:
www.bing.com:443 + serverNames: ["www.bing.com"] succeeds.
- Other tested targets such as Cloudflare/Apple/Amazon also succeeded in the same environment.
This suggests the failure is target-handshake-size dependent rather than a UUID/key/shortId/flow mismatch.
Expected behavior
REALITY should either:
- handle valid target TLS Certificate records slightly larger than 8192 bytes, or
- expose a clearer error such as
target TLS record too long: 8273 > 8192, or
- document that target TLS records must be <= 8192 bytes and that large OCSP-stapled certificate records are unsupported.
Actual behavior
The connection is reset and server logs only:
handshake did not complete successfully
This makes it look like a generic REALITY handshake/authentication failure, even though the specific cause appears to be the target Certificate record exceeding the hardcoded 8192 byte limit.
Integrity requirements
Description
VLESS + TCP + REALITY + Visionfails when usingwww.microsoft.com:443as REALITYdest/serverNameson Xray-corev26.3.27.This is not a direct TLS rejection by Microsoft: direct
openssl s_clientandcurlfrom the same server towww.microsoft.com:443succeed. The failure appears to be caused by the REALITY server-side target handshake parser rejecting a Microsoft TLS Certificate record whose length is slightly larger than the hardcoded8192byte limit ingithub.com/xtls/reality.In this environment, Microsoft returns a TLS Certificate record length that leads REALITY to log
Certificate: 8273, which is larger thansize = 8192, and then the REALITY connection is rejected withhandshake did not complete successfully.Environment
Xray 26.3.27 (Xray, Penetrates Everything.) d2758a0 (go1.26.1 linux/amd64)xtls-rprx-visionwww.microsoft.com:443/www.microsoft.comchromeSanitized server config shape
{ "log": { "loglevel": "debug" }, "inbounds": [ { "listen": "0.0.0.0", "port": 443, "protocol": "vless", "settings": { "clients": [ { "id": "<redacted-uuid>", "flow": "xtls-rprx-vision" } ], "decryption": "none" }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "show": true, "dest": "www.microsoft.com:443", "xver": 0, "serverNames": ["www.microsoft.com"], "privateKey": "<redacted>", "shortIds": ["<redacted>"] } } } ], "outbounds": [{ "protocol": "freedom", "tag": "direct" }] }Client uses matching VLESS REALITY settings with:
Reproduction
dest: "www.microsoft.com:443",serverNames: ["www.microsoft.com"],show: true.Observed client-side result:
REALITY debug log
Relevant sanitized server-side REALITY logs:
Direct TLS to Microsoft succeeds
From the same server, direct TLS to Microsoft succeeds:
openssl s_client -connect www.microsoft.com:443 -servername www.microsoft.com -tls1_3 -brief </dev/nullOutput excerpt:
curl https://www.microsoft.com/also returns HTTP 200 from the same server.Microsoft Certificate record size
With
openssl -msg, Microsoft returns a Certificate record that can exceed the REALITY hardcoded size limit when OCSP/status is involved:openssl s_client -connect www.microsoft.com:443 -servername www.microsoft.com -tls1_3 -status -msg </dev/nullRelevant output:
0x204c + 5 = 8273, matching the REALITY debug log line:Suspected root cause
In
github.com/xtls/realitytls.go, the current code appears to have a hardcoded 8192 byte limit:For this Microsoft target, REALITY computes:
So the target TLS handshake is rejected as too long, and the connection fails with:
Control test
Using the same UUID/key/flow/shortId/client, changing only the REALITY target to another site succeeds. For example:
www.bing.com:443+serverNames: ["www.bing.com"]succeeds.This suggests the failure is target-handshake-size dependent rather than a UUID/key/shortId/flow mismatch.
Expected behavior
REALITY should either:
target TLS record too long: 8273 > 8192, orActual behavior
The connection is reset and server logs only:
This makes it look like a generic REALITY handshake/authentication failure, even though the specific cause appears to be the target Certificate record exceeding the hardcoded
8192byte limit.