# Cache and transport fingerprints

> **Transport preservation is automatic only inside cache-enabled HTTPS connections.** Without a
> cache suffix, Litport leaves CONNECT opaque and does not terminate the client's TLS connection.
> With cache mode, Litport attempts to reproduce the supported fingerprint *shape* on origin-bound
> misses and bypasses; unsupported input uses one verified standard TLS profile instead. A cache hit makes
> no origin connection at all.

```docs-figure
cache-fingerprint-lanes
The cache suffix is the boundary. Opaque requests keep the client's encrypted application transport; intercepted misses use a new verified TLS connection with compatible shape; hits stop at the hub.
```

This feature reduces transport differences introduced by HTTPS interception. It does not impersonate
a different client: curl remains curl, Chrome remains Chrome, and a mobile app keeps the compatible
traits Litport actually observed from that app.

## Exactly when it runs

The existing password suffix enables both caching and transport-shape preservation:

```text
PASSWORD_cache-images,fonts
PASSWORD_cache-all_cacheduration-30
```

Litport attempts preservation when all of these are true:

1. The client uses the Litport HTTP proxy endpoint and sends `CONNECT` for an HTTPS target.
2. The password contains a valid cache suffix and authentication succeeds.
3. The hub's cache and certificate authority are ready, so Litport accepts cache interception.

If the password has no cache suffix, the CONNECT tunnel stays opaque. Litport forwards the client's
TLS records and encrypted HTTP bytes without reading or rewriting them. “Unchanged” refers to the
application transport through Litport: the target still sees the selected proxy exit IP and that
exit's TCP/IP behavior, not the customer's local network identity.

If cache interception cannot be admitted before CONNECT begins, Litport keeps the existing opaque
path. Plain HTTP targets, SOCKS5 ingress, and HTTP/3/QUIC do not enter this feature.

## What happens on the wire

A cache-enabled CONNECT has two independent TLS connections:

```text
client ── TLS leg 1 ──> Litport hub ── TLS leg 2 ──> verified HTTPS origin
           Litport CA       cache        public Web PKI
```

The implementation processes them in this order:

1. **Observe the ClientHello.** A bounded, memory-only observer reassembles the first TLS handshake
   message across TLS records while passing the exact input to the verified standard TLS stack. The
   captured bytes live only inside that CONNECT and are never used as cryptographic material.
2. **Complete the client handshake.** The client verifies the target certificate issued by the
   Litport cache CA. Litport verifies that TLS SNI matches the authenticated CONNECT authority.
3. **Parse HTTP safely.** The negotiated ALPN selects the inbound HTTP/1.1 or HTTP/2 server. Bounded
   observers retain only the ordering and connection settings needed for reproduction.
4. **Check the local cache.** A hit is returned immediately. There is no origin socket, ClientHello,
   HTTP request, or target-side fingerprint for that hit.
5. **Keep the selected route.** A miss or intercepted bypass opens the origin through the same
   Litport route, product, pool, geography, and accounting path already selected for the request.
   Preservation never performs its own direct DNS route around the proxy.
6. **Create fresh origin TLS.** Litport sanitizes the observed profile, creates new cryptographic
   values, verifies the origin hostname and certificate chain, and offers the compatible observed
   protocols. The origin's ALPN result chooses HTTP/1.1 or HTTP/2 on that same live connection.
7. **Serialize the request.** Litport emits the supported HTTP shape, streams request and response
   bodies, and applies the ordinary cache and decoded-byte accounting rules.

No raw ClientHello, header block, JA3/JA4 value, or per-client profile identifier is written to
persistent storage or operational logs.

## What is preserved—and what must be new

```docs-figure
cache-fingerprint-layers
Preservation covers stable observable TLS and HTTP shape. Connection secrets and network identity must differ because interception creates a separate origin connection.
```

### TLS ClientHello shape

For a supported ClientHello, Litport preserves compatible observable structure such as:

- protocol-version and cipher-suite ordering;
- extension ordering and safe compatible extension contents;
- supported-group, signature-algorithm, point-format, and ALPN ordering;
- key-share group order, certificate-compression choices, GREASE positions, and compatible padding.

Every origin connection gets a fresh client random, session ID, and key share. Litport removes PSK
identities and binders, keeps only an empty session-ticket offer when that extension was present, and
does not replay early data, TLS cookies, or other connection-bound material. A GREASE ECH placeholder
is regenerated safely in the same position; a real ECH payload is not replayed. Opaque extensions are
rejected by default; the reviewed exception is the empty, stateless OpenSSL extension pair used by
common curl builds.

### HTTP/1.1 shape

Litport preserves the order and original casing of fields that remain after proxy sanitation,
including repeated field positions. Proxy-only credentials are always stripped. Message framing is
reconstructed from the parsed body, so `Content-Length` or `Transfer-Encoding` remains valid even when
its observed position and casing can be retained. Fields added only by the HTTP parser are not mistaken
for client input or forwarded as part of the shape, and Litport does not add a default `User-Agent` when
the client sent none.

Upgrades, `Expect: 100-continue`, malformed framing, or an observer/parser mismatch use deterministic
standard HTTP serialization. They do not cause Litport to change the TLS profile halfway through a
CONNECT.

### HTTP/2 shape

Litport preserves supported initial SETTINGS order and values, connection WINDOW_UPDATE behavior,
pre-request PRIORITY frames, per-request HEADERS priority, pseudo-header order, and regular field
order. A single Cookie field remains one field instead of being split at semicolons, and an absent
`User-Agent` remains absent. A request with no body ends on its initial HEADERS frame instead of
gaining a synthetic empty DATA frame. Request metadata is isolated per stream so concurrent requests
cannot borrow another stream's shape.

Exact HPACK bytes and dynamic-table history are not a compatibility promise. Responses, cache hits,
concurrency, and connection reuse can make the two compression histories diverge even when the same
fields appear in the same order.

## Implementation boundaries

The preservation state belongs to one authenticated CONNECT. It is never shared across customers,
tokens, target authorities, or later client connections.

| Stage | Bound and lifetime | If observation cannot be reproduced safely |
| --- | --- | --- |
| ClientHello | Up to 64 KiB, memory-only, for the current CONNECT | Use one verified standard TLS profile for that CONNECT |
| HTTP/1.1 request observation | Up to 72 KiB for an active header/trailer block and 16 queued pipelined headers | Use deterministic HTTP/1.1 serialization on the already chosen TLS identity |
| HTTP/2 connection observation | Up to 64 KiB from the client preface through the first HEADERS frame | Use deterministic HTTP/2 defaults on the already chosen TLS identity |
| Origin connections | A private HTTP/1.1 or HTTP/2 pool owned by the current CONNECT | Close the pool when the CONNECT ends; never share TLS or compression history with another client |

For HTTP/1.1, the observer tracks fixed-length and chunked bodies—including trailers—so bytes inside
a body cannot be mistaken for the next pipelined request. Before applying an observed field sequence,
Litport matches the method, request target, and canonical field/value counts against the parsed
request. Proxy authentication fields are removed regardless of their observed position.

For HTTP/2, Litport combines two views. A frame-level observer captures the initial SETTINGS,
connection WINDOW_UPDATE, and pre-request PRIORITY frames. The HTTP/2 decoder attaches only the
current stream's pseudo-header order, regular-field order, and HEADERS priority to that request's
in-memory context. The origin transport then uses those values on the matching stream, which prevents
concurrent requests from borrowing each other's ordering or priority.

When the client CONNECT ends, Litport closes both the protocol pool and every raw origin socket owned
by it. This also terminates an HTTP/2 read loop that is still retiring its final stream; it cannot live
on and become available to a later CONNECT.

The origin socket is always opened through Litport's already selected upstream route. Hostname and
public-chain verification remain enabled. The HTTP engine is chosen from the origin's ALPN result on
that same socket; Litport does not reconnect just to obtain a preferred protocol. If an HTTP/2 client
reaches an HTTP/1.1-only origin, the request uses ordered HTTP/1.1.

## Why a fully identical fingerprint is impossible

TLS interception cannot preserve the complete connection byte for byte. Litport is one TLS server to
the client and a separate TLS client to the target. Reusing the first connection's secrets on the
second connection would be invalid and insecure.

The following necessarily differ or may diverge:

| Signal | Why it cannot be identical |
| --- | --- |
| TLS randoms, key shares, binders and transcript | They are cryptographically bound to one handshake. |
| Session tickets, PSK identity and 0-RTT | A ticket issued for the client-to-Litport leg is not valid at the origin. |
| Server certificate and ServerHello | The client sees a Litport-issued target certificate; Litport sees the origin's public certificate. |
| TCP SYN, source address and operating-system stack | The target connection originates from the selected proxy exit. |
| TLS records, packet sizes and timing | Buffering, routing, cache lookup, scheduling and network conditions create new boundaries. |
| HTTP/2 flow control, reuse and HPACK history | Hits remove requests from the origin leg and both connections evolve independently. |

The honest guarantee is therefore **compatible transport fingerprint-shape preservation**, not full
fingerprint preservation. It targets the stable features commonly consumed by JA3, JA4, and HTTP/2
fingerprinting while keeping all connection-bound material fresh.

## Fallback and failure rules

Safety takes priority over resemblance:

- A supported capture uses the sanitized preserved TLS profile for every origin connection belonging
  to that client CONNECT.
- An oversized, malformed, or unsafe ClientHello uses the verified standard TLS profile for that
  entire CONNECT. Litport never alternates two TLS identities within one client tunnel.
- Request-specific HTTP metadata can fall back to deterministic standard serialization without
  changing the CONNECT's chosen TLS profile.
- If a preserved origin handshake has sent bytes and fails, Litport returns an origin error. It does
  not retry with a contradictory ClientHello or weaken certificate verification.
- Every origin dial is restricted to the authenticated CONNECT authority and still uses the selected
  upstream route.

Customers see cache hit, miss, and bypass, plus free bytes and savings, in Traffic statistics and the
[Account API](/docs/api/usage). Transport preservation has no customer-facing per-request status.

## Client and protocol behavior

| Client or protocol | Cache-enabled behavior |
| --- | --- |
| curl, SDKs and command-line clients | Works when that process trusts the Litport cache root. Their own compatible TLS/HTTP shape is reproduced; they are not changed into browsers. |
| Chrome, Firefox and browser automation | HTTP/1.1 and HTTP/2 shape can be preserved. The browser profile must trust the Litport root without disabling certificate checks. |
| Android and iOS apps you control | Works when the app's effective trust configuration accepts the Litport root and the app does not pin the target certificate. |
| Certificate-pinned apps | Cache interception fails by design. Remove the cache suffix to use an opaque tunnel. |
| Real ECH | Its encrypted payload is bound to the original server configuration and cannot be replayed on Litport's separate origin TLS leg; cache interception is unsupported. |
| HTTP/3/QUIC | Not part of the TCP CONNECT cache path. Applications may negotiate HTTP/2 instead. |
| Plain HTTP and SOCKS5 | Never intercepted by this feature. They keep their existing uncached behavior. |

See [certificate setup](/docs/proxy-cache/certificate) for per-client trust instructions.

## Verify with a fingerprint endpoint

For an optional external check, make one opaque request and one cache-enabled intercepted request
through the same hub. The endpoint below returns JA3, JA4, HTTP/2, and TCP observations:

```bash
# Opaque: Litport does not terminate TLS
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD' \
  'https://tls.peet.ws/api/all'

# Intercepted bypass: extensionless diagnostic URL is not stored, but transport preservation runs
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-images' \
  --cacert litport-cache-root.crt \
  'https://tls.peet.ws/api/all'

# A second independent JA3/JA4 and HTTP/2 view
curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD' \
  'https://tls.browserleaks.com/json'

curl --proxy 'http://hub-us-7.litport.net:PORT' --proxy-user 'USER:PASSWORD_cache-images' \
  --cacert litport-cache-root.crt \
  'https://tls.browserleaks.com/json'
```

Compare `tls.ja3_hash`, `tls.ja4`, the ordered TLS fields, and the HTTP/2 fingerprint. Do not compare
`client_random`, `session_id`, source IP, TCP fingerprint, or timing; those are expected to change.
On the BrowserLeaks response, the equivalent fields are `ja3_hash`, `ja4`, and `akamai_hash`.
This is a third-party diagnostic service, so it will observe the proxy exit IP and request metadata.
Use it only when that disclosure is acceptable.

## Further reading

The Litport blog post
[TLS fingerprinting through a proxy: JA3 and JA4](/blog/tls-fingerprinting-through-a-proxy-99688) explains
how opaque tunnels, intercepting proxies, and cache mode each affect JA3, JA4, and HTTP/2 fingerprints, with
measured results for common clients.

Return to the [cache overview](/docs/proxy-cache) or review
[eligibility and troubleshooting](/docs/proxy-cache/reference).
