You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have read the documentation and understand the configuration items I reference below.
I searched existing issues/PRs/discussions and did not find a duplicate.
I am not piling up options; the request is a single, minimal capability.
This is a feature/enhancement request, not a support question.
Summary
XHTTP correlates the uplink and downlink of the split modes (packet-up, stream-up) with a session ID that is emitted on the wire as a canonical lowercase UUIDv4 (8-4-4-4-12 hex with hyphens). Its textual format is fixed in the client and cannot be changed via configuration.
That makes the session ID a static protocol fingerprint. Some commercial L7 CDNs / reverse-proxies that terminate TLS and run a WAF match this exact pattern and return 403, which breaks XHTTP through them while leaving no config-level remedy.
Request: allow the session ID (and the seq counter) to be emitted in a non-canonical textual form, analogous to the existing xPaddingObfsMode. Because both peers are Xray, the encoding is implicit and needs no negotiation, and it can be delivered to stock clients through the share-link extra.
In the split modes the session ID must appear in an inspectable HTTP channel:
path → /<base>/<uuid>
query → ?<key>=<uuid>
cookie → Cookie: <key>=<uuid>
header → <key>: <uuid>
(sessionPlacement: "path" is currently rejected at config build — see #5631 — leaving query / cookie / header.)
The downlink is a long-lived GET with no body, so the session ID cannot be moved into the request body (the one channel such WAFs typically don't inspect). Consequently, in every configuration the canonical UUID is visible on the wire.
Observed against a commercial TLS-terminating L7 CDN: a request containing a canonical UUIDv4 in the value of any of path / query / cookie / header is answered 403. Trivial textual variations pass the same WAF (verified): _ instead of -; a file extension appended to the token; hyphen-less hex; percent-encoded separators. In other words the block keys on the canonical textual shape, not on entropy or length as such.
Why existing options don't solve it
sessionPlacement / sessionKey, seqPlacement / seqKey — change the channel and the key name, not the value's textual format. The value stays a canonical UUID → still matched.
xPaddingObfsMode / xPaddingKey / xPaddingMethod — obfuscate padding only, not the session/seq values.
downloadSettings (asymmetric transport) — both halves still share the same visible session ID to correlate; the half that traverses the WAF is still blocked.
finalmask — operates below/around TLS on the byte stream; it does not (and cannot, through a TLS-terminating L7 proxy) rewrite the plaintext HTTP session ID.
The only remedy available today is a source patch to session-ID generation, which is not deployable to a subscriber base running stock clients.
Reproduction
Server: VLESS + XHTTP inbound, mode: packet-up.
Put any L7 reverse-proxy in front that returns 403 when a canonical UUIDv4 appears in the request line / query / cookie / header value. Minimal repro with nginx:
stream-one — avoids the session ID, but the uplink is a single long-lived POST body, which such proxies buffer to completion before forwarding → deadlock/timeout.
No sessionPlacement / sessionKey / padding combination passes.
Add an extra option to obfuscate the session/seq wire representation, mirroring xPaddingObfsMode:
"extra": {
"sessionObfs": true
}
When enabled, the client encodes the 128-bit session value (and the seq counter) in a textual form that is not a canonical UUID — e.g. base64url, base62, or hyphen-less hex — and the server decodes it accordingly.
Correlation semantics are unchanged (still a 128-bit token); only the on-wire spelling differs.
Both peers are Xray, so the encoding is implicit — no negotiation needed.
Deliverable to stock clients via the share-link extra, consistent with how XHTTP already distributes low-frequency transport knobs.
Optionally an enum instead of a bool, if multiple encodings are wanted:
A fixed canonical-UUID token in the request URL is a static distinguisher regardless of this specific WAF. Making it obfuscatable improves XHTTP's generic middlebox / DPI resilience — the transport's stated purpose. Padding already has an obfuscation switch; the session/seq tokens are the remaining fixed textual fingerprint.
Integrity requirements
Summary
XHTTP correlates the uplink and downlink of the split modes (
packet-up,stream-up) with a session ID that is emitted on the wire as a canonical lowercase UUIDv4 (8-4-4-4-12hex with hyphens). Its textual format is fixed in the client and cannot be changed via configuration.That makes the session ID a static protocol fingerprint. Some commercial L7 CDNs / reverse-proxies that terminate TLS and run a WAF match this exact pattern and return
403, which breaks XHTTP through them while leaving no config-level remedy.Request: allow the session ID (and the seq counter) to be emitted in a non-canonical textual form, analogous to the existing
xPaddingObfsMode. Because both peers are Xray, the encoding is implicit and needs no negotiation, and it can be delivered to stock clients through the share-linkextra.Environment
mode: packet-up,security: tlsProblem detail
In the split modes the session ID must appear in an inspectable HTTP channel:
/<base>/<uuid>?<key>=<uuid>Cookie: <key>=<uuid><key>: <uuid>(
sessionPlacement: "path"is currently rejected at config build — see #5631 — leaving query / cookie / header.)The downlink is a long-lived GET with no body, so the session ID cannot be moved into the request body (the one channel such WAFs typically don't inspect). Consequently, in every configuration the canonical UUID is visible on the wire.
Observed against a commercial TLS-terminating L7 CDN: a request containing a canonical UUIDv4 in the value of any of path / query / cookie / header is answered
403. Trivial textual variations pass the same WAF (verified):_instead of-; a file extension appended to the token; hyphen-less hex; percent-encoded separators. In other words the block keys on the canonical textual shape, not on entropy or length as such.Why existing options don't solve it
sessionPlacement/sessionKey,seqPlacement/seqKey— change the channel and the key name, not the value's textual format. The value stays a canonical UUID → still matched.xPaddingObfsMode/xPaddingKey/xPaddingMethod— obfuscate padding only, not the session/seq values.downloadSettings(asymmetric transport) — both halves still share the same visible session ID to correlate; the half that traverses the WAF is still blocked.finalmask— operates below/around TLS on the byte stream; it does not (and cannot, through a TLS-terminating L7 proxy) rewrite the plaintext HTTP session ID.The only remedy available today is a source patch to session-ID generation, which is not deployable to a subscriber base running stock clients.
Reproduction
Server: VLESS + XHTTP inbound,
mode: packet-up.Put any L7 reverse-proxy in front that returns
403when a canonical UUIDv4 appears in the request line / query / cookie / header value. Minimal repro with nginx:Connect with a stock client:
packet-up— uplink/downlink carry the UUID →403.stream-one— avoids the session ID, but the uplink is a single long-lived POST body, which such proxies buffer to completion before forwarding → deadlock/timeout.sessionPlacement/sessionKey/ padding combination passes.Proposed solution (minimal, follows existing precedent)
Add an
extraoption to obfuscate the session/seq wire representation, mirroringxPaddingObfsMode:When enabled, the client encodes the 128-bit session value (and the seq counter) in a textual form that is not a canonical UUID — e.g. base64url, base62, or hyphen-less hex — and the server decodes it accordingly.
extra, consistent with how XHTTP already distributes low-frequency transport knobs.Optionally an enum instead of a bool, if multiple encodings are wanted:
Rationale beyond this one CDN
A fixed canonical-UUID token in the request URL is a static distinguisher regardless of this specific WAF. Making it obfuscatable improves XHTTP's generic middlebox / DPI resilience — the transport's stated purpose. Padding already has an obfuscation switch; the session/seq tokens are the remaining fixed textual fingerprint.
Related
sessionPlacement: "path"rejected at build