· 7 min read ·

QUIC's Stateless Design Leaks More Infrastructure Than You'd Expect

Source: lobsters

The Observation Surface Nobody Talked About

When QUIC was being designed and later standardized as RFC 9000, a lot of the security discussion centered on what it hides. Payload encryption from the first byte. Encrypted packet numbers after the handshake. Minimal plaintext header fields compared to TCP. The QUIC invariants document explicitly limits what middleboxes can see, and that was the point: years of experience with TCP had shown that anything visible to network equipment eventually gets ossified, manipulated, or monetized by someone in the path.

What got less attention was what QUIC still exposes on the server side, specifically to someone actively probing rather than passively observing. A recent paper highlighted on the APNIC blog demonstrates this gap clearly: using QUIC’s own stateless response mechanisms as a measurement primitive, researchers can infer the deployment configurations of major content providers without any cooperation from those providers and without decrypting anything.

The technique is called QUIC backscatter, and understanding how it works requires understanding two design decisions in RFC 9000 that are individually sensible and together create a rich inference surface.

Stateless Resets and Version Negotiation

QUIC is a UDP-based protocol, and unlike TCP, there is no kernel-level connection state that survives a server restart. When a QUIC server restarts, it loses all its session records. Clients attempting to resume those sessions will send packets carrying connection IDs the server no longer recognizes. RFC 9000 defines the Stateless Reset mechanism to handle this gracefully: the server generates a short response packet containing a token derived from the connection ID using a keyed hash. The client sees the token, recognizes it as a valid stateless reset for its connection, and knows to start a new handshake rather than waiting indefinitely.

The critical property here is that generating a Stateless Reset requires no per-connection state. The server receives a packet with an unknown connection ID, computes HMAC(key, connection_id), formats a response, and sends it back to the source address in the packet. No lookup. No session table. Just arithmetic.

Version Negotiation works similarly. When a QUIC server receives an Initial packet advertising a version number it doesn’t support, it responds with a Version Negotiation packet listing the versions it does support. Again, this is stateless and happens before any cryptographic handshake.

Both mechanisms share a property that makes them useful for measurement: the server will send a packet to an address it has never verified, in response to a packet it has never authenticated, with content that carries structural information about its own implementation.

Send a crafted QUIC packet to any QUIC-capable server. If the connection ID you fabricate doesn’t match any live session, you’ll likely receive a Stateless Reset. If the QUIC version you claim isn’t supported, you’ll receive a Version Negotiation packet. You didn’t need to complete a handshake. You didn’t need to prove you’re a legitimate client. The server told you something about itself before it knew who it was talking to.

Connection IDs Are Not Random

For a single server, Stateless Resets are interesting but not particularly revealing. The signal becomes meaningful when you consider how large deployments work.

QUIC was explicitly designed to support connection migration: a client can change its IP address mid-connection, and the server uses the Connection ID to find the right session state rather than the source address. This creates a requirement that QUIC deployments at scale need their Connection IDs to be routable. A load balancer sitting in front of a thousand QUIC servers needs to be able to look at a packet’s Connection ID and decide which backend to forward it to, without consulting a per-connection lookup table that would itself become a scalability bottleneck.

The IETF recognized this requirement early enough that there’s an entire draft standard for it: QUIC-LB, which defines how servers can encode routing information inside Connection IDs in a way that load balancers can decode. The encoding can be plaintext (routing information directly readable) or encrypted (routing information decryptable only by the load balancer using a shared key). Both variants have specific structural properties: fixed-length fields in fixed positions, a server ID encoded in a defined number of bits, a nonce for uniqueness.

Even when the routing information is encrypted, the structure itself is visible. A 12-byte Connection ID with the first byte as a length indicator, the next 4 bytes as an encrypted server ID, and the remaining bytes as a nonce looks structurally distinct from a 16-byte Connection ID with a different layout. Two servers returning Connection IDs with identical structural layouts are almost certainly running the same QUIC-LB configuration. Two servers returning structurally different Connection IDs despite being announced under the same IP prefix are likely running independent software stacks.

For hypergiants like Google, Cloudflare, and Meta, whose QUIC deployments span thousands of machines across dozens of countries, this structural consistency is not accidental. It reflects deliberate engineering decisions about how to manage a global fleet. Cloudflare has written publicly about their use of encrypted Connection IDs for routing across their edge. Google’s original QUIC implementation, documented in their 2014 SIGCOMM paper, included similar mechanisms for routing at scale. The consistency needed for operational correctness is the same consistency that makes the deployment legible to an outside observer.

What Backscatter Reveals About Anycast

Hypergiants make heavy use of anycast routing: a single IP address announced from many locations simultaneously, with BGP routing each client to the topologically nearest node. When you connect to 1.1.1.1, you reach one of Cloudflare’s locations, but you have no direct way to know which one or how many exist.

The traditional approach to anycast measurement is distributed active probing: send packets to the anycast address from many vantage points around the world and cluster the results by RTT. Platforms like RIPE Atlas make this tractable, with thousands of probes placed in networks globally. It works, but it requires access to the probing platform and produces noisy results where probe density is low.

QUIC backscatter offers a complementary approach that doesn’t require distributed infrastructure. Because Stateless Reset and Version Negotiation are both generated per-packet rather than per-connection, you can send many probes to the same anycast address in a short window, vary the source addresses across a range you control, and correlate the Connection ID structures in the responses.

If two source addresses in different parts of a darknet receive responses with structurally identical Connection IDs but different encoded routing values, you’ve confirmed that BGP routed those probes to different anycast sites, that both sites are running the same QUIC-LB configuration, and that the routing values encode different backend servers within their respective sites. If the Connection ID structures differ entirely, the sites may be running different software generations. If one address receives a response and another receives nothing, that can indicate asymmetric routing or location-specific deployment.

Compared to RTT clustering, this gives you qualitatively different information. RTT tells you roughly how many anycast sites exist and where they are. Connection ID analysis tells you whether those sites are running the same deployment, which software version they’re on, and how their load balancing is configured. For an operator managing a global rollout, those details are the hard part. For an outside observer, they’re surprisingly accessible.

The Practical Implications for Anyone Deploying QUIC

The hypergiants are the research subjects in this work because they’re large enough to study statistically, but the same analysis applies to any organization deploying QUIC at scale.

If you’re running a QUIC service behind a load balancer, your Connection ID format is a structural fingerprint of your deployment. An observer can determine whether you’re using QUIC-LB or a custom scheme, roughly how many backends you have, and whether your load balancing is consistent-hash-based or ephemeral. If you add capacity, the fingerprint changes. If you run different software versions on different clusters, that’s visible in the Connection ID structure.

None of this leaks user data or cryptographic material. But it does leak information that operators may prefer to keep internal: how many servers you run, how your deployment is organized, when you’re in the middle of a rollout. For most organizations, this is low-stakes. For hypergiants whose infrastructure topology has competitive intelligence value, or for operators with threat models that include targeted attacks against specific backend clusters, it’s worth thinking about.

The QUIC-LB draft’s encrypted CID format helps, but doesn’t eliminate the issue. Even with encrypted routing fields, the structural layout of the CID (field lengths, positions, total length) reveals which QUIC-LB configuration profile you’re using. Suppressing Stateless Resets entirely would close the measurement surface, but at the cost of degraded client experience when session state is lost. Rate-limiting resets reduces the measurement bandwidth but doesn’t prevent the inference.

For the network measurement community, the more important point is methodological. QUIC backscatter is a new primitive that complements existing techniques. Combined with ZMap-style scanning to enumerate QUIC-capable hosts, BGP data from RouteViews and RIPE RIS to understand address space allocation, and RTT-based anycast enumeration for geographic placement, it produces a deployment graph that is substantially more detailed than what was available from passive observation alone.

TCP gave researchers visibility into flows. QUIC, with its operational requirements for stateless responses and structured Connection IDs, gives researchers visibility into the server topology behind those flows. The protocol was designed to limit what middleboxes can observe. It turns out to be more legible than expected to anyone willing to probe it directly.

The pattern here extends beyond QUIC. Operational requirements consistently create measurement opportunities. DNS’s recursive resolution structure exposes query patterns to resolvers. TLS session resumption tokens can be used for cross-site tracking even when cookies are blocked, as documented in RFC 8446’s discussion of ticket reuse. HTTP/2’s flow control and push mechanisms expose server behavior to timing analysis. Each time a protocol solves an operational problem, the solution becomes an observable behavior. QUIC backscatter is the latest example, and probably not the last.

Was this interesting?