Summary

  • TLS 1.3 0-RTT lets a returning client send application data with its ClientHello, avoiding one or two round trips. The early data is encrypted, but unlike ordinary 1-RTT data it has no guarantee of non-replay between connections.
  • RFC 8470 gave HTTP a resource-level answer that TLS could not invent: carry possible early-data history across intermediaries with Early-Data: 1, and let an origin return 425 Too Early when it is unwilling to risk processing the request.
  • A 425 retry keeps the request’s intended operation but changes its cryptographic time. The client should retry automatically, and that retry must not use early data. HTTP/3 retained the same replay rules over QUIC.

The shortcut began before the server spoke

A conventional secure request waits. The client and server exchange handshake messages, derive fresh traffic secrets and establish the conditions under which application data will travel. Only then does the browser or API client send the HTTP operation. On a distant path, even light itself makes that sequence visible as delay.

TLS 1.3 created a faster path for clients that had recently spoken to a server. A server can issue resumption material; on a later connection the client presents that remembered state and may place application data beside its ClientHello. The request no longer waits for the new ServerHello. In HTTP, this “early data”, or 0-RTT, can remove the one or two round trips that would otherwise precede the request.

The optimisation did not make the handshake irrelevant. It moved useful work ahead of fresh confirmation. That distinction is the entire history behind 425.

The TLS 1.3 specification is explicit about the weaker bargain. Early data is not forward secret because it is encrypted under keys derived from the offered pre-shared key. More narrowly, it has no guarantee of non-replay between connections. Ordinary TLS 1.3 application data depends on the new ServerHello and its server random; 0-RTT data cannot, because it has already left the client.

This does not mean that 0-RTT is plaintext, unauthenticated or freely mutable. An attacker cannot make the same early bytes appear twice inside one connection, nor turn them into ordinary 1-RTT data. The exposed boundary is more precise: a captured early flight may be presented on another connection.

Replay and retry can meet without being the same

Network software has always retried. A client loses a response, a connection breaks, or a user presses a button again. These are imperfect but visible decisions by an endpoint. A replay, in the sense used by RFC 8470, is an attacker’s duplication without the client’s knowledge.

The two can compound. Imagine a distributed service with two zones that do not possess identical replay state. An attacker copies a ClientHello and its early request toward both. Zone A accepts and acts on the 0-RTT data. Zone B refuses early data but completes a full handshake. If the attacker hides A’s answer, the client can continue with B and legitimately resend what it believes was never processed. One operation has now arrived twice by two different mechanisms.

TLS 1.3 describes both classes. A server can record recent ClientHellos, consume session tickets once, use freshness windows or assign one authoritative ticket zone. These measures can constrain direct duplication. They demand difficult consistency across machines, regions and restarts. The standard calls acceptance at most once per server instance a minimum and recommends tighter limits where practical.

Yet the retry-assisted class cannot be solved inside TLS. The cryptographic layer sees records and handshakes; it does not know that a message redeems a token, books a seat, records an audit event or merely fetches an inert stylesheet. It cannot decide what “safe twice” means.

That is why TLS 1.3 forbids application protocols from casually enabling 0-RTT. A protocol needs a profile that states which interactions can use it and what happens when a server rejects it. A TLS library must not independently turn early data on or automatically resend rejected bytes. Those are application decisions.

A method name was evidence, not a verdict

HTTP seemed to have a convenient vocabulary for that decision. GET and HEAD are defined as safe methods; PUT and DELETE are idempotent; POST often carries a change. A client without better information may send safe methods in early data and must not send a method known to be unsafe or of unknown safety.

But RFC 8470 refused to confuse method semantics with a complete model of the resource. A nominally safe request can increment a meter, consume a one-time signed URL, warm an expensive backend, change a cache or trigger logging whose duplication matters. Replaying an otherwise idempotent operation many times can exhaust a limit or reveal timing information. Conversely, an application with explicit transaction design can know more than the method token reveals.

Only the origin normally possesses that resource-specific knowledge. The client controls whether it sends early. The TLS endpoint controls whether it accepts an early flight. A gateway sees routing. The application knows consequences. HTTP needed a way for the last of these actors to veto the optimism of the first three without disabling the feature everywhere.

Three ways to refuse premature effects

RFC 8470 describes three equally valid protections.

First, the server can reject the entire early flight at TLS. This is simple and broad. TLS does not selectively keep one early HTTP request while discarding another, so every request in that flight loses the latency advantage.

Second, the HTTP server can delay processing until the handshake completes. It may parse headers or choose a route while carefully avoiding effects, then release each request when fresh connection state exists. In a multiplexed protocol, different requests can have different policies even though they arrived together.

Third, the server can answer one request with 425 Too Early. The status says the server is unwilling to risk processing a request that might be replayed. It returns the decision to the client, which can send the request again after leaving early data.

The third choice matters because it turns 0-RTT from a global switch into a resource-level privilege. A public asset may take the fast path while a token redemption waits. The origin does not have to pretend that both actions share one risk profile.

One bit had to survive the gateway

The origin that understands the resource may not terminate the client’s TLS connection. A browser can speak to a CDN; the CDN can forward to a gateway; the gateway can call an application. By the time the request reaches the code that knows its consequences, the original handshake is several hops away.

RFC 8470 therefore defined the Early-Data request field with a single valid value, 1. An intermediary that forwards before its client-side handshake completes must add it. An intermediary that sees it must not remove it. If a request might already have been forwarded by another instance, the bit stays set.

This tiny field carries history rather than preference. It does not say “please go fast”. It says that some upstream copy may have existed while replay was possible, and that the user agent understands the 425 recovery contract.

That history cannot be washed away by waiting for a later handshake. Suppose a CDN received the request in early data, marked it, and opened an ordinary fully established connection to the origin. The origin cannot declare the request safe merely because its own hop is now 1-RTT. The possible duplicate belongs to the previous hop. If the marked request cannot be processed safely, the origin must return 425.

Multiple or malformed instances are treated as the same single risk bit. The field does not appear in responses or request trailers. It is deliberately too small to become an ornate trust claim: it preserves the one fact downstream actors need.

What 425 changes—and what it keeps

When a user agent sent a request in early data and receives 425, it should retry automatically. The decisive rule is that the retry must not itself be early data. The client waits for the handshake and then transmits ordinary application data.

The URI need not change. The method need not change. The payload and intended operation need not change. Unlike a redirect, 425 does not nominate another resource. Unlike 421, it does not say the selected connection lacks authority for the origin. The same server may be entirely healthy and ready to serve the request a moment later.

The status is also not 429 rate limiting or 503 service unavailability. It offers no quota and no general “later” interval. The missing condition is a completed cryptographic context, not spare capacity. It is not 100 Continue either: that informational response helps a client decide whether to send a body, while 425 is a final refusal to process a possibly replayed request.

A server should not emit 425 for an ordinary request that neither arrived in early data nor carried the header. Without that evidence, the server cannot assume that the client knows the special retry rule. The response is not cacheable by default, and its body is not a representation of the requested resource. The IANA registry records the narrow name “Too Early” and points to RFC 8470.

Intermediaries cannot all repair the same history

An intermediary can always forward a 425. If the request arrived with Early-Data: 1, it must do so: the replay exposure began upstream, beyond the intermediary’s power to clear.

There is one deliberately asymmetric case. If the intermediary itself received the request as early data, and the request did not arrive already marked from a previous hop, it may absorb the 425 and retry toward the origin. Before doing so it must wait for the client-facing handshake to complete. The same edge that knows where the early history began can move that request into a safe moment.

A gateway must not forward early requests to an origin unless it knows the origin understands the header and can generate 425 correctly. Otherwise the gateway should wait or refuse. Enabling 0-RTT at the edge while hiding it from an unaware application would let infrastructure volunteer the application for a risk it cannot see.

Action time matters more than arrival time

An HTTP request can straddle the handshake boundary. Headers may arrive early and a body later. In QUIC, stream scheduling can even deliver data labelled as early after the handshake completes. A wall-clock observation of the last byte is therefore insufficient.

RFC 8470 asks when the server begins to act. Parsing enough to identify a route can be harmless; committing a transaction, launching a backend call or mutating a cache may not be. If any instance can initiate effects before completion, every instance that might receive a replay must enforce the same safety invariant.

This is a distributed-systems rule disguised as a status code. Instances may use different mitigations—one rejects early data, another waits, a third emits 425—but none may act early on a request that another instance would treat differently. A newly restarted node lacks the replay history accumulated before startup and should refuse 0-RTT while its recording window overlaps that blind period.

HTTP/3 kept the boundary alive

Moving HTTP from TCP to QUIC did not remove the issue. RFC 9114 explicitly applies RFC 8470’s replay mitigations to HTTP/3 0-RTT. The handshake is TLS inside QUIC; the application data is carried in streams; the obligation remains.

HTTP/3 adds a separate compatibility question. A client sending early requests has not yet received the new connection’s SETTINGS, so it relies on values remembered from the previous session. A server must reject 0-RTT if it cannot prove those remembered values are compatible with its current settings. If it accepts the data, its later SETTINGS cannot reduce limits in a way the early request might already have violated.

SETTINGS compatibility is not the 425 decision. One protects the protocol’s shared state; the other protects the resource’s effects. Their coexistence shows how many kinds of proof a request used to get for free by waiting.

HTTP 425 made one of those proofs explicit. “Too early” does not describe the age of the content or the impatience of the user. It describes a moment in which the request has arrived before its path can safely authorize consequences.

Sources and evidence limits

The protocol record is TLS 1.3, RFC 8446, Using Early Data in HTTP, RFC 8470, HTTP/3, RFC 9114, and the current IANA HTTP Status Code Registry. These sources establish the specified latency trade, replay boundary, intermediary duties, recovery rule and HTTP/3 continuity. They do not establish present deployment share, universal client support, a named exploitation incident, measured savings for any service or exactly-once application behavior.