TLS 1.3 Early Data Moves Replay Risk Into HTTP Request Semantics

A returning client can possess a TLS 1.3 resumption ticket and send an HTTP request before a new handshake has completed. That removes a round trip from the request path, but it also changes a security property that ordinary application code often assumes: accepted encrypted traffic is not necessarily unique to one connection.

TLS 1.3 early data, commonly called 0-RTT data, is protected with keys derived from a pre-shared key associated with an earlier session or provisioned out of band. The request is encrypted, yet its protection does not depend on the fresh ServerHello from the new connection. As a result, TLS does not provide the same cross-connection replay protection for early data that it provides for application data sent after the handshake.

The latency gain therefore crosses an application trust boundary. A server deciding to accept early data is also deciding that some application operations may arrive again.

Encryption and replay resistance are separate properties

A captured early-data record is not plaintext. An observer without the relevant secrets cannot simply alter its protected contents and produce a valid record. The security limitation is narrower: a valid first flight can potentially be presented again in another connection context.

TLS 1.3 explicitly treats this as a weaker property of 0-RTT. Server-side anti-replay mechanisms can reduce exposure, but the protocol does not give clients a general guarantee that early application data will be accepted only once across connections.

That distinction matters for requests with durable effects. Replaying a request that reads an immutable public object may have little application impact. Replaying a request that creates an order, consumes a one-time capability, triggers a transfer, rotates a credential, or records an irreversible state transition can duplicate an effect even though every replayed byte remains cryptographically authentic.

Authentication does not remove this condition. A request can be validly associated with an account and still be unsafe to execute twice. Replay resistance is a property of the interaction, not merely of the identity attached to it.

Session tickets create the path to 0-RTT

Early data is tied to pre-shared-key operation. A server can issue a TLS 1.3 NewSessionTicket that permits a later client connection to offer the resulting PSK. The ticket can also advertise a maximum early-data size. Possessing suitable resumption state allows the client to construct its first application records without waiting for the new handshake to finish.

Acceptance remains a server choice. A server receiving the early-data indication can reject the early data and continue with a normal handshake, request another ClientHello through HelloRetryRequest, or accept early data when the required PSK and associated parameters match.

The TLS decision is coarse. Once a server accepts early data at the TLS layer, it cannot use that layer to accept one early request while rejecting another based on HTTP semantics. The transport knows record protection and handshake state; the application knows whether a specific operation can tolerate replay.

This split is the architectural reason HTTP needs its own early-data handling.

HTTP carries replay state across intermediary hops

Reverse proxies and gateways complicate the boundary because the TLS connection that receives early data may terminate before the origin application. The origin might see an ordinary HTTP request on a separate backend connection and otherwise have no signal that the request arrived through a replay-exposed client flight.

HTTP defines the Early-Data request header for this propagation. An intermediary that forwards a request before completion of the client-side TLS handshake marks the request with Early-Data: 1. An intermediary must not remove the marker when it is present.

The marker represents history, not current transport state. Waiting for the backend TLS handshake to finish cannot erase the fact that a request was already conveyed in early data on a previous hop. If that earlier flight is replayed, another copy may already have entered the application path.

This makes consistent proxy behavior part of the security model. A fleet in which one edge delays replay-sensitive requests while another forwards them immediately does not provide a stable policy. The application effect is governed by the least restrictive path that can accept the replay.

425 Too Early is an application refusal

HTTP status 425 Too Early gives a server a precise response when processing a replay-exposed request is not acceptable. A client that sent a request in early data can retry after receiving 425, but the retry is sent after the handshake rather than as early data.

The status code is not a generic transient-failure response. It communicates that the request was refused because possible replay changes the safety of processing it at that point.

An origin behind a gateway can use the same mechanism when it receives Early-Data: 1. This preserves the decision at the component that has enough context to classify the operation. The edge can optimize transport latency without pretending to know whether a particular endpoint mutates durable state, consumes a token, or invokes an external system.

A gateway also cannot safely forward replay-exposed requests to an origin that has no compatible early-data policy. Forwarding first and relying on a later handshake event does not retract an effect already committed by the origin.

HTTP method names are useful but incomplete policy inputs

HTTP defines safe methods as methods whose requested semantics are essentially read-only, which makes method classification a useful starting point for early-data policy. It is not a complete security control.

A nominally safe request can still encounter application behavior with side effects. Analytics writes, cache population, rate-limit consumption, signed-URL accounting, backend job creation hidden behind a read endpoint, or application defects can make replay observable. Conversely, an operation with explicit idempotency machinery may tolerate duplicate delivery more safely than its method name alone suggests.

The relevant question is whether repeating the exact authenticated operation can cause an unacceptable effect. That decision may depend on resource semantics, credentials, nonce handling, transaction design, and downstream systems.

Idempotency keys can reduce duplicate effects when the application stores and enforces them across every execution path that matters. They do not turn TLS early data into non-replayable transport. Their protection is application state, with its own retention period, scope, atomicity, and failure modes.

Distributed anti-replay state has a consistency cost

TLS 1.3 describes server mechanisms for limiting replay, including recording information associated with accepted early data. In a single process, maintaining such state can be straightforward. A distributed service has a harder problem.

If several edge nodes can accept the same resumption material but do not share sufficiently consistent replay state, copies of one early flight can reach different nodes during a replication gap. Routing a ticket to one tightly coordinated acceptance domain can reduce that exposure, but it introduces deployment and availability trade-offs.

A global, strongly consistent replay database can also consume enough coordination to erode the latency benefit that motivated 0-RTT. Operators therefore face a real trade-off rather than a switch that makes early data equivalent to ordinary post-handshake traffic.

TLS anti-replay controls remain valuable, but application protocols are still required to restrict early data to interactions that can tolerate the residual risk. A server-side replay cache is not a basis for clients to assume exactly-once execution.

Rejection and retry create another duplication edge

A server can reject early data, after which an application may retransmit the request once the handshake completes. Automatic retry needs care because the client and server can have different information about whether an earlier attempt produced an effect.

At the TLS layer, rejection means the server did not accept that connection’s early data for processing. In a multi-hop HTTP deployment, however, replay history can originate on a previous connection and be represented by the Early-Data header. The origin must treat that marker as evidence that another copy could exist rather than as a promise about the current hop.

Retries also interact with ordinary application failure modes. A connection can fail after a server commits a transaction but before the client receives the response. Early-data controls do not solve that general ambiguity. Operations requiring strong duplicate suppression still need application-level transaction identities or equivalent durable mechanisms.

The performance boundary belongs at request classification

Enabling 0-RTT for an entire HTTPS service because some endpoints are replay-tolerant places the decision at the wrong layer. The transport can advertise and accept early data, but request processing still needs a policy that distinguishes operations whose effects can safely occur more than once from operations that require a completed handshake.

For many services, the practical design is selective: permit early processing only for a narrow set of requests with known replay-tolerant semantics, and delay or reject the rest. In deployments with intermediaries, the replay marker has to survive every hop until the component making that decision.

The resulting architecture treats 0-RTT as a latency optimization with weaker cross-connection guarantees, not as a faster form of ordinary TLS application data. Its security boundary is set by the effect of a duplicate request, the consistency of every accepting server instance, and the durability of any application mechanism used to suppress repeated effects.