Highlights
- Fixes a Hysteria server crash: a late write on a released UDP link panicked in a detached goroutine and took the whole process down.
- Mux.Cool over a Hysteria server no longer corrupts streams. Concurrent sessions used to interleave frame headers and payloads.
- The REALITY server again authenticates clients whose Client Hello does not offer X25519MLKEM768, such as sing-box with a Chrome fingerprint. Before this release they fell back to the cover target.
- XHTTP inbounds accept Mux.Cool TCP sessions; upstream accepts only pure XUDP there. In packet-up and stream-up, the server can optionally poke an idle downlink with a padded Mux.Cool KeepAlive, so CDNs and reverse proxies do not cut it as idle (#16, contributed by Medium1992).
- Merges upstream Xray-core v26.9.8, v26.9.9, v26.9.30, and later upstream/main fixes through
7da5dae6. This adds the MASQUE inbound/outbound/transport, the XDRIVE transport, the rewritten XDNS finalmask, and the FinalMask-based transport dialer/listener. - Builds with Go 1.27.1 and
-tags http2legacy. While a TLS handshake hangs, XHTTP over HTTP/2 shares one pending dial again instead of opening a connection per request (XTLS#6797).
Fork fixes
- Hysteria server link ownership.
Server.Processtook UDP readers, writers and links from async.Pooland released them whenDispatchLinkreturned. Outbound tasks and mux/XUDP workers keep using the link after that point, so a late write hit a nil writer and panicked. A reused pooled object could also deliver data to another session. Links are now allocated per session and the pools are removed; per-packet zero-copy parsing is unchanged. The unused pooled-writer API incommon/bufis removed with them. - Hysteria TCP and Mux.Cool framing. The TCP link writer now serializes whole frames. Before, an Xray client with mux enabled could receive another session's frame headers inside its TCP data.
- Mux.Cool carrier check. Mux.Cool workers start only for TCP destinations. A UDP packet addressed to
v1.mux.cool, for example over a Hysteria UDP session, is dispatched like any other packet. - REALITY key shares. Upstream
xtls/reality20260908062103 rejects every Client Hello without an X25519MLKEM768 key share. The server now runs from an in-tree copy of that module version,third_party/reality, with one change: a hello that offers the hybrid group in neithersupported_groupsnorkey_shareauthenticates through its X25519 key share. Hellos that offer the hybrid group keep upstream's rules. Unauthenticated connections still reach the cover target unchanged. - XDNS finalmask hardening (on top of the upstream rewrite):
- A fragmented query shorter than its fragment header no longer panics the server before authentication.
- DNS-over-TCP resolvers send the RFC 1035 two-byte length prefix.
- Per-client fragment counters no longer accumulate.
- A full send queue returns an error instead of blocking.
- TCP and UDP resolvers can be closed during a stalled write.
- Resolver redials publish their address atomically.
- FinalMask settings. An unknown, corrupt or misplaced mask now returns an error instead of panicking. This applies both when loading a configuration and when adding inbounds/outbounds through the HandlerService API.
- MASQUE resource lifetime:
- The server releases every queued packet when a tunnel closes, including when it closes before its writer starts.
- The client sends Packet Too Big ICMP replies through one bounded writer instead of starting a goroutine per oversized packet.
- XHTTP Mux.Cool KeepAlive shutdown. The idle-downlink KeepAlive loop could write a frame after a Mux.Cool worker reported closed. It now checks for shutdown after building each frame and right before writing it. Shutdown itself never waits for the loop, so a write stuck on a stalled connection cannot hold
Close. The idle timer uses the monotonic clock, so a wall-clock step cannot stretch or skip a KeepAlive. - Build tooling.
vformatskips vendoredthird_partymodules so they stay byte-identical to upstream. The codename now reads(Jolymmiles).
Upstream changes
Previous fork releases were based on upstream v26.7.28. This release merges upstream v26.9.8, v26.9.9 and v26.9.30, plus upstream/main through 7da5dae6. Notable changes:
- New protocols and transports:
- MASQUE (IETF CONNECT-IP, RFC 9484) inbound, outbound and transport, including HTTP/2 Extended CONNECT.
- XDRIVE remote-storage transport with Google Drive and template backends.
- Transport and FinalMask:
- Transports are built on FinalMask's dialer and listener.
udpHopis a FinalMask UDP mask; noise masks supportexp.- XDNS finalmask is rewritten and gains new parameters, and its resolver-close deadlock and socket leaks are fixed.
- Proxies:
- Shadowsocks 2022 is refactored without sing* dependencies.
- XTLS Vision suppresses the outer CloseNotify after switching to direct copy.
- Blackhole supports a custom response.
- Freedom compatibility and
dialerProxyhandling are improved. - HTTPUpgrade sends Sec-WebSocket-* headers.
- The Hysteria outbound no longer truncates UDP datagrams with ChromeParrot.
- WireGuard:
- Startup, close and packet-view release are fixed.
- The outbound endpoint IP is fixed.
- Idle UDP flows hold less memory.
- The inbound answers ICMP ping.
- kernelTun IPv6 table allocation is fixed.
- TUN and system:
- Linux gains
autoSystemDNS; Windows gainsautoSystemWfpBlockLeak, adapter reuse, and startup when IPv6 is disabled. - UDP packet destinations are preserved with traffic stats.
- Linux gains
- Clients and runtime:
- The mux client
Dispatch/SessionManager.Closerace is fixed. - The gRPC client no longer redials with a canceled first-request context.
- The XHTTP
WaitReadCloserdata race is fixed. - The buffered writer handles payloads larger than its remaining capacity.
- The QUIC sniffer handles zero-filled datagram tails.
- Geodata matchers use less memory.
- The mux client
- Dependencies: Go 1.27.x,
golang.org/x/net0.59.0,google.golang.org/grpc1.84.0.
Compatibility notes
- Build tag. Release assets are built with Go 1.27.1 and
-tags http2legacy. Builds from source should use the same tag. Without it, Go 1.27's x/net HTTP/2 client opens one connection per waiting request while a TLS handshake hangs, soxmux.maxConnectionsno longer bounds XHTTP connections. The tag also keeps the H2MUX and MASQUE servers on x/net's own HTTP/2 server, as in Go 1.26 builds. Moving the XHTTP client tonet/http.Transportso the tag can be dropped is planned separately. - REALITY. The client-version check stays outside the key-share change.
minClientVerandmaxClientVerremain optional operator settings with no implicit minimum. The HHMM stamp is display-only: REALITY still sends the three version bytes, now 26.10.5. - XDNS configuration changed upstream.
domainsentries takenames,typesand limits;resolversentries takeaddrs. Update XDNS configurations, and run clients and servers from compatible versions. udpHopis configured as a FinalMask UDP mask (udphop) instead of underquicParams. QuicParams protobuf field 5 is reserved.- WireGuard outbound. The
remoteDNS"local" mode anddomainStrategywere removed upstream. - FakeDNS. The default IPv6 pool changed upstream to
2001:2::/48. - Mux.Cool. Only TCP carriers start Mux.Cool, which matches every client implementation.
- Mux.Cool over XHTTP. This is intentional fork behavior; upstream (XTLS#4128) discourages stacking it on XHTTP's own multiplexing. Server-side KeepAlive options:
xhttpSettings.muxKeepAliveSecs: a seconds range, e.g."20-25".xhttpSettings.muxKeepAliveBytes: a padding range, capped at 1024 bytes.- Both are off by default. stream-one is never poked, and only Xray clients use Mux.Cool.
- When enabled, the server sends a small frame after each randomized idle gap. That pattern is visible as record timing outside TLS and to a TLS-terminating CDN.
- Fields 30 and 31 of the splithttp
Configprotobuf are fork-owned.
- Wire format. VLESS, Trojan, REALITY, Vision and SMUX wire bytes are unchanged.
Validation
All local gates ran on Linux/amd64 with Go 1.27.1 and GOFLAGS=-tags=http2legacy.
- Release commit
57e9ec41, local gates:- vformat, protobuf-header check,
go vet ./...andgo test ./...; - race for REALITY, VLESS, SMUX, mux, Hysteria, MASQUE, XHTTP, XDNS and FinalMask;
- checkptr for REALITY and VLESS;
- version test (
26.10.5-1858).
- vformat, protobuf-header check,
- Process interoperability. An Xray server on the release commit was tested with Xray, sing-box and Mihomo clients:
- VLESS TCP TLS/REALITY × no-flow/Vision 36/36 (three runs);
- SMUX 24/24;
- H2MUX 24/24;
- Hysteria 3/3, plus Mux.Cool over Hysteria with carrier teardown;
- Mux.Cool over XHTTP 6/6 (Xray clients only). A counting relay saw KeepAlive frames during a 3.5 s silence only with the option on and outside stream-one: 717 bytes versus 0.
- Regression tests. Each fix has one, and each was observed failing before its fix:
- Hysteria link lifetime and Mux.Cool framing;
- Mux.Cool UDP carriers;
- REALITY hellos without the hybrid group;
- the XDNS bounds, prefix and resolver-close cases;
- FinalMask invalid masks;
- the MASQUE queue drain and ICMP bound;
- the XHTTP single-dial check (16 waiting requests → 1 TCP connection);
- the XHTTP Mux.Cool KeepAlive shutdown.
- Pre-release Validation passed on
57e9ec41, with 529 tests passing and none failing:- repository-wide unit, race and checkptr;
- SMUX and H2MUX matrices three times;
- stress and reconnect profiles, and the hardening cycles;
- the direct, legacy-mux, XUDP, reverse and WireGuard version-skew gates;
- the candidate-versus-v26.8.25-1457 performance and resource budgets (three runs);
- the RemnaNode configuration contract;
- a 30-minute mixed-path soak (65 cycles).
- Tests and Checkings passed on the same commit.
- Release-flag Linux/amd64 build: static,
-tags=http2legacy,GOAMD64=v1,CGO_ENABLED=0,-trimpath. - Code review. The upstream sync and fork fixes went through eight review rounds. The XHTTP Mux.Cool changes (#16 and its follow-up #18) went through two independent rounds plus review bots. Every finding was fixed, or answered with a written reason in the pull request.
- These results are correctness and compatibility evidence. No performance improvement or traffic-camouflage gain is claimed.
Release assets
GitHub Actions had a major outage when this release was published, and release.yml could not get a hosted runner in two attempts. The six assets were therefore built on Linux/amd64 from the tag, with the same commands and inputs as release.yml:
- Go 1.27.1,
CGO_ENABLED=0, defaultGOAMD64=v1/GOARM64=v8.0. go build -tags http2legacy -trimpath -buildvcs=false -gcflags="all=-l=4" -ldflags="-X github.com/xtls/xray-core/core.build=v26.10.5-1858 -s -w -buildid=" ./main- Geodata from Loyalsoldier/v2ray-rules-dat, checked against its published SHA-256.
- The same ZIP layout and
.dgstformat as earlier releases.
Binary SHA-256:
Xray-linux-64:f1f08963a7be97f0d37efb7df5f3af1f762ce3d1c63a5eb5b779aed8f9227a11Xray-linux-arm64-v8a:03eb450e50a46859cda1c5b5591d68acc34052f2a07d0b52bba3cf5fee07a9b1
The released amd64 binary also passed the VLESS 12/12, SMUX and XHTTP Mux.Cool process gates as both server and Xray client.
Verified against CI. After Actions recovered, release.yml ran on the tag without uploading. Its xray binaries for linux/amd64 and linux/arm64 are byte-identical to the released ones (same SHA-256 as above), and so are the geodata, README and LICENSE in the packages.