Back to HTTP Headers

Early-Data security request

Automatically added by intermediaries to flag a request sent during TLS 1.3's 0-RTT early data phase, which is vulnerable to replay attacks.

What it does

Early-Data is set (typically by a TLS-terminating proxy or load balancer, not by application code) on requests that arrived as part of TLS 1.3's 0-RTT (zero round-trip time) "early data" — a performance optimization letting a client send request data immediately, before the TLS handshake fully completes, on a connection resuming a previous session. The catch: 0-RTT data is inherently vulnerable to replay attacks, since a network attacker who captures the encrypted early data packet can resend it, and the server (without additional protection) has no way to distinguish the legitimate original request from a malicious replay.

Early-Data: 1 exists specifically so application-layer code can detect "this specific request arrived via early data" and apply appropriate caution — most importantly, not treating it as safe for non-idempotent operations unless the application has its own replay protection.

Syntax

Early-Data: 1

There's only one meaningful value. The header is either present (indicating this request was 0-RTT early data) or absent (normal request, no special replay risk from this mechanism).

Why 0-RTT requests are replay-vulnerable

TLS 1.3's 0-RTT resumption lets a returning client skip a full round trip by using a previously-negotiated session key to send encrypted application data immediately, before the server confirms the new session is valid. This is a genuine performance win (saving a full round trip on repeat connections), but it comes with a structural weakness: because the server hasn't yet completed a live handshake exchange with the client, it can't cryptographically distinguish a legitimately resent connection attempt from an attacker capturing and replaying the same encrypted early-data packet.

Idempotent operations (a GET that just reads data) are generally safe even if accidentally processed twice. Non-idempotent operations (a POST that charges a payment, sends an email, or creates a record) are exactly where a replay could cause real harm — charging twice, sending duplicate emails, or creating duplicate records.

How servers should handle it

  • Reject or defer non-idempotent operations arriving as early data. A server (or an intermediary in front of it) that sees Early-Data: 1 on a request that would perform a non-idempotent action should either reject it (respond 425 Too Early, a status code created specifically for this scenario) or hold it until the full TLS handshake completes before processing.
  • Allow it for genuinely idempotent, safe operations. GET requests fetching non-sensitive, cacheable content are generally fine to process immediately even as early data, since the performance benefit is real and the replay risk is low-consequence for that class of request.
  • Application-layer replay protection can override the default caution. If your application has its own idempotency mechanism (idempotency keys, for example), you can safely process early-data requests for operations that would otherwise be risky, since your own mechanism independently guards against duplicate processing.

Common mistakes and gotchas

Application code never checking for this header at all. Since Early-Data is often added by infrastructure (a TLS-terminating load balancer or CDN) rather than being something application developers think about day-to-day, it's easy to have 0-RTT enabled at the infrastructure layer without any corresponding application-layer awareness of replay risk for sensitive endpoints.

Enabling 0-RTT broadly without auditing which endpoints could be affected. Turning on TLS 1.3 0-RTT support at the infrastructure level is often a simple config flag, but the actual safety of doing so depends on your application correctly distinguishing safe-to-replay from unsafe-to-replay operations — this requires actual endpoint-level review, not just a performance-motivated config toggle.

Confusing 425 Too Early with other 4xx errors. 425 Too Early is a status code created specifically for early-data rejection scenarios — using a more generic status code (like a plain 403) for this specific situation loses the semantic clarity that a well-behaved client could use to understand it should simply retry once the full handshake completes.

Assuming early data is inherently dangerous and disabling 0-RTT entirely. For read-heavy, idempotent-request-dominated workloads, 0-RTT's performance benefit can be substantial with minimal real risk — outright avoiding TLS 1.3 0-RTT everywhere throws away a real performance win that, with proper request-type awareness, can be used safely.

Real-world examples

A request arriving via 0-RTT early data:

GET /api/public/status HTTP/2
Early-Data: 1

Safe to process immediately — idempotent, non-sensitive read.

Server rejecting a non-idempotent request arriving too early:

POST /api/payments/charge HTTP/2
Early-Data: 1

HTTP/2 425 Too Early

The client should retry after the full TLS handshake completes, at which point the request will arrive without Early-Data: 1.

FAQ

Do I need to manually set the Early-Data header in my application code?

No — it's added automatically by the TLS-terminating layer (your web server, load balancer, or CDN) when a request arrives via 0-RTT early data. Your application code only needs to check for its presence, not set it.

What should my server do when it sees Early-Data: 1?

For idempotent, low-risk operations, process normally. For non-idempotent or sensitive operations (payments, account changes, anything with real-world side effects), either reject with 425 Too Early or hold the request until the full TLS handshake completes, unless you have independent application-layer replay protection.

Does enabling TLS 1.3 0-RTT automatically make my application vulnerable to replay attacks?

Not automatically — but it does introduce the possibility if your application doesn't correctly handle the Early-Data header for non-idempotent operations. The vulnerability comes from not accounting for replay risk on sensitive endpoints, not from 0-RTT itself being enabled.

What's the performance benefit of 0-RTT that makes this trade-off worth considering?

It eliminates a full round trip on repeat connections to a server the client has recently connected to, which can meaningfully reduce latency for returning visitors — particularly valuable on high-latency mobile networks where every round trip has real, noticeable cost.

Fun fact

425 Too Early (RFC 8470, the same RFC that defines Early-Data) is one of the more recently introduced HTTP status codes with a genuinely narrow, specific purpose — unlike most 4xx codes that cover broad categories of client error, 425 exists for exactly one scenario: telling a client "your request arrived too early in the connection lifecycle for me to safely process it yet, please retry." It's a good illustration of how new transport-layer optimizations (0-RTT) sometimes require entirely new application-layer vocabulary to communicate their edge cases safely.

Related Headers