Skip to content

[XHTTP] Session ID format (UUID with dashes) is detectable by CDN/DPI systems #6264

Description

@euppi98

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:

  1. Real browser traffic almost never contains UUID v4 in URL path segments in this exact format
  2. The pattern is consistent and machine-detectable
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions