Summary
Some CDN providers and DPI systems block XHTTP traffic by detecting the standard UUID format (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) used as session ID in URL paths and HTTP headers. This makes sessionPlacement: "path" (the default) and sessionPlacement: "header" unusable on certain CDNs, regardless of other obfuscation settings.
Problem
XHTTP uses a standard RFC 4122 UUID (with dashes) as a session identifier. When sessionPlacement is path (default), the URL looks like:
POST /mypath/550e8400-e29b-41d4-a716-446655440000/3
When sessionPlacement is header, the UUID is placed in a custom header:
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000
Some CDN providers detect and block requests containing the UUID pattern [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} in both URLs and headers. This is a reliable XHTTP fingerprint because:
- Real browser traffic almost never contains UUID v4 in URL path segments in this exact format
- The pattern is consistent and machine-detectable
- It appears in every single XHTTP request regardless of other obfuscation settings
Reproduction
The following tests demonstrate the detection pattern on a CDN that blocks XHTTP:
UUID with dashes in path → blocked:
curl https://cdn.example.com/mypath/550e8400-e29b-41d4-a716-446655440000/0 \
-X POST \
-H "Content-Type: application/grpc" \
-d "testdata"
# → HTTP/2 403
UUID without dashes in path → allowed:
curl https://cdn.example.com/mypath/550e8400e29b41d4a716446655440000/0 \
-X POST \
-H "Content-Type: application/grpc" \
-d "testdata"
# → HTTP/2 200
Random non-UUID string in path → allowed:
curl https://cdn.example.com/mypath/abc123/0 \
-X POST \
-H "Content-Type: application/grpc" \
-d "testdata"
# → HTTP/2 200
UUID with dashes in header → blocked:
curl https://cdn.example.com/mypath \
-X POST \
-H "X-Request-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/grpc" \
-d "testdata"
# → HTTP/2 403
Non-UUID value in header → allowed:
curl https://cdn.example.com/mypath \
-X POST \
-H "X-Request-ID: abc123" \
-H "Content-Type: application/grpc" \
-d "testdata"
# → HTTP/2 200
Short non-UUID value in header → allowed:
curl https://cdn.example.com/mypath \
-X POST \
-H "X-Request-ID: user-12345" \
-H "Content-Type: application/grpc" \
-d "testdata"
# → HTTP/2 200
The pattern is clear: any value matching the standard UUID format with dashes is blocked, regardless of which header or URL segment it appears in.
Additional blocked patterns discovered
During testing, the following combinations also trigger blocking:
# POST + Cookie header → blocked
curl https://cdn.example.com/mypath \
-X POST \
-H "Cookie: session_id=abc123" \
-d "testdata"
# → HTTP/2 403
This means sessionPlacement: "cookie" is also unusable on this CDN.
Impact
sessionPlacement: "path" (default) — blocked due to UUID in URL
sessionPlacement: "header" — blocked due to UUID in header value
sessionPlacement: "cookie" — blocked due to POST+Cookie detection
sessionPlacement: "query" — likely blocked due to UUID in query string (not tested, same pattern)
In practice, all sessionPlacement options are blocked on CDNs that perform UUID pattern matching.
Proposed Solutions
Option 1 — Add session ID encoding option
Add a new parameter sessionEncoding (or similar) to control how the session ID is formatted:
{
"sessionEncoding": "base62"
}
Possible encodings:
"uuid" — current default, standard RFC 4122 format with dashes
"hex" — UUID without dashes: 550e8400e29b41d4a716446655440000
"base62" — Base62 encoded: 2vBqrkmCDJyWZa9n8s4Pxt (looks like a token)
"base64url" — URL-safe Base64: VQ6EAOKbQdSnFkZlVEA
Base62 would be ideal as it:
- Has no special characters, works in URLs, headers, and cookies
- Looks like an authentication token (natural CDN traffic)
- Has no recognizable pattern for automated detection
- Is already used by
xPaddingMethod: "tokenish"
Option 2 — Hash-based session ID
Instead of using the raw UUID, derive the session ID from HMAC(UUID, shared_secret). This would:
- Eliminate the UUID pattern entirely
- Add an extra layer of authentication
- Make session IDs look like random tokens
Option 3 — Configurable session ID length and charset
Allow users to configure the character set and length of session IDs independently of the UUID source, similar to how xPaddingMethod: "tokenish" already generates token-like padding.
Related
- The
xPaddingMethod: "tokenish" option already solves a similar problem for padding values by generating Base62 tokens instead of repeated X characters
- The January 2025 commit added
sessionPlacement options specifically to help disguise session IDs — but the UUID format itself remains detectable regardless of placement
- This issue is the next logical step after that commit
Environment
- Xray-core: latest
- Transport: XHTTP (
xhttpSettings)
- Mode:
packet-up
- Issue reproduced with: multiple independent CDN providers
Summary
Some CDN providers and DPI systems block XHTTP traffic by detecting the standard UUID format (
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx) used as session ID in URL paths and HTTP headers. This makessessionPlacement: "path"(the default) andsessionPlacement: "header"unusable on certain CDNs, regardless of other obfuscation settings.Problem
XHTTP uses a standard RFC 4122 UUID (with dashes) as a session identifier. When
sessionPlacementispath(default), the URL looks like:When
sessionPlacementisheader, the UUID is placed in a custom header:Some CDN providers detect and block requests containing the UUID pattern
[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}in both URLs and headers. This is a reliable XHTTP fingerprint because:Reproduction
The following tests demonstrate the detection pattern on a CDN that blocks XHTTP:
UUID with dashes in path → blocked:
UUID without dashes in path → allowed:
Random non-UUID string in path → allowed:
UUID with dashes in header → blocked:
Non-UUID value in header → allowed:
Short non-UUID value in header → allowed:
The pattern is clear: any value matching the standard UUID format with dashes is blocked, regardless of which header or URL segment it appears in.
Additional blocked patterns discovered
During testing, the following combinations also trigger blocking:
This means
sessionPlacement: "cookie"is also unusable on this CDN.Impact
sessionPlacement: "path"(default) — blocked due to UUID in URLsessionPlacement: "header"— blocked due to UUID in header valuesessionPlacement: "cookie"— blocked due to POST+Cookie detectionsessionPlacement: "query"— likely blocked due to UUID in query string (not tested, same pattern)In practice, all sessionPlacement options are blocked on CDNs that perform UUID pattern matching.
Proposed Solutions
Option 1 — Add session ID encoding option
Add a new parameter
sessionEncoding(or similar) to control how the session ID is formatted:{ "sessionEncoding": "base62" }Possible encodings:
"uuid"— current default, standard RFC 4122 format with dashes"hex"— UUID without dashes:550e8400e29b41d4a716446655440000"base62"— Base62 encoded:2vBqrkmCDJyWZa9n8s4Pxt(looks like a token)"base64url"— URL-safe Base64:VQ6EAOKbQdSnFkZlVEABase62 would be ideal as it:
xPaddingMethod: "tokenish"Option 2 — Hash-based session ID
Instead of using the raw UUID, derive the session ID from HMAC(UUID, shared_secret). This would:
Option 3 — Configurable session ID length and charset
Allow users to configure the character set and length of session IDs independently of the UUID source, similar to how
xPaddingMethod: "tokenish"already generates token-like padding.Related
xPaddingMethod: "tokenish"option already solves a similar problem for padding values by generating Base62 tokens instead of repeatedXcharacterssessionPlacementoptions specifically to help disguise session IDs — but the UUID format itself remains detectable regardless of placementEnvironment
xhttpSettings)packet-up