Engineering research / networking

Envoy 1.40.0: HTTP/3 and QUIC Declared Stable, Post-Quantum Key Exchange by Default, Route Specifiers, Event-Driven Drain and the Breaking Build and MCP Router Changes

Envoy 1.40.0 (13 October 2026): QUIC and HTTP/3 promoted to stable, a hybrid post-quantum curve in the default TLS key exchange, route specifiers, event-driven drain, and incompatible changes to the Bazel build, MCP router header forwarding and the Rust dynamic module ABI.

By Sandeep Belgavi · Published 2026-10-25 · Prepared 2026-10-19

Recent development · Practical technical guide · 19 October 2026

Envoy 1.40.0 (13 October 2026): QUIC and HTTP/3 promoted to stable, a hybrid post-quantum curve in the default TLS key exchange, route specifiers, event-driven drain, and incompatible changes to the Bazel build, MCP router header forwarding and the Rust dynamic module ABI.

The release in one paragraph

Envoy 1.40.0 was tagged on 13 October 2026. The version history groups changes into incompatible behaviour changes, minor behaviour changes, bug fixes, removed configuration and new features, and this release has substance in every group. The headline features are the promotion of QUIC and HTTP/3 to stable, including upstream HTTP/3 and all QUIC extensions, a post-quantum hybrid key exchange added to the default curves, and a new routing extension point. The headline breaks are a build migrated to Bazel modules with a custom registry, an MCP router that stops forwarding the client's authorization header by default, and a Rust dynamic module hook signature change made to close a use-after-free. The security section carries forward the 1.39.x fixes, including the OAuth2 and API key CONNECT crashes that the Istio 2026-007 bulletin covered on 15 October.

QUIC and HTTP/3 are stable

The notes say it in one line: QUIC and HTTP/3 are promoted from alpha to stable, including all QUIC extensions and upstream HTTP/3. In the same release QUIC listeners gain client certificate support, so mutual TLS works over HTTP/3 on the downstream side; upstream QUIC gains client certificates; and the P-384 and P-521 curves are supported. For operators who kept HTTP/3 behind a flag because of the alpha label, this is the release to re-evaluate it, and the QUIC guide covers what changes at the transport. The usual cautions remain: UDP must reach the listener through every load balancer and firewall on the path, and the HTTP/3 use-after-free fixed in the 1.39.x line is a reminder that a newly stable stack still gets security fixes.

Post-quantum key exchange by default

The TLS stack adds X25519MLKEM768, the hybrid of X25519 and the ML-KEM post-quantum key encapsulation, to the default ECDH curves for both upstream and downstream TLS, including FIPS builds. The behaviour can be reverted with the runtime flag envoy.reloadable_features.pqc_default_ecdh_curves. The practical effect is that any peer that also supports the hybrid, which includes current browsers and many servers, negotiates it automatically after the upgrade; peers that do not fall back to the classical curves. Two things to check before rolling out: the ClientHello grows by roughly a kilobyte with the hybrid key share, which has tripped middleboxes and TLS terminators that assumed a single-packet hello; and upstream TLS to legacy services should be tested, because a service that mishandles unknown groups will fail the handshake rather than ignore the group. The TLS guide explains the handshake these changes sit in.

Route specifiers and the new load balancers

Routing gains an extension point called route_specifiers that runs after route matching and may refine, drop or synthesise the matched route, at the route configuration, virtual host and route levels. Two implementations ship with it: a priority-group cluster specifier and a dynamic-module route specifier, so a module written in Rust, Go or C++ can choose the upstream after Envoy has done the matching. Load balancing adds a per_worker_subset policy that decouples the per-worker pool size from the cluster size, and a load_aware_locality policy that picks localities by headroom derived from ORCA load reports; coalesced rebuilds of the load balancer on batched EDS updates are now on by default. A long-standing surprise is also closed: container-aware CPU limit detection, which 1.37 claimed to enable, was in fact only active with the cpuset-threads flag; it now applies whenever concurrency is not set explicitly, and can still be disabled. If you run Envoy in a pod with a CPU limit and never set concurrency, the worker count may change after this upgrade.

Drain is event-driven, and the admin endpoint drains properly

Drain-close decisions for the HTTP connection manager and the TCP, Mongo, Redis, Thrift and generic proxies are now derived from a drain event pushed to each connection when the drain sequence starts, rather than polled per response. This fixes the Mongo, Redis, Thrift and generic proxies ignoring inbound-only drains, and is guarded by envoy.reloadable_features.use_connection_event_drain, read once per connection. Two related changes alter what the admin endpoint does. A non-graceful drain_listeners call now starts a drain sequence and notifies the covered connections instead of only stopping the listeners, honouring the configured drain strategy; and connections of a filter chain being replaced are notified with the configured strategy instead of immediately, so the default gradual strategy ramps them down over the drain window. Deployment tooling that called the non-graceful endpoint expecting a hard stop will see connections drained first. UDP proxies get session handoff during hot restart, so connectionless listeners no longer go dark between parent and child. These interact with the pod termination sequence described in the pod termination guide.

The incompatible changes, with the action for each

ChangeWho is affectedAction
Bazel WORKSPACE removed; Envoy, the API and the docs are Bazel modules; a custom registry is requiredAnyone building Envoy or an extension against itMigrate to MODULE.bazel and add the envoyproxy bazel-registry alongside the BCR; follow the bazel/tests/external example
Hermetic LLVM bumped from 18 to 22; clang with libc++ is the default; libc++ and libstdc++ flags removedDownstream buildsDrop --config=clang; use --config=gcc only if you need it
Wasm engine selected with a Bazel build setting; the old define flags fail the buildCI scriptsSwitch to the proxy-wasm-cpp-host engine setting
AWS-LC removed as an SSL library, with the FIPS configppc64le buildsUse --config=openssl
mcp_router no longer forwards downstream headers, including authorization, by defaultMCP gateways aggregating backendsConfigure header_forwarding per backend; forward_all true restores the old behaviour, but prefer audience-bound tokens
Rust dynamic module HttpFilter hooks take a shared referenceEvery Rust dynamic moduleMove per-stream mutable state behind Cell or RefCell; ensure Drop cannot panic
Local rate limiter no longer short-circuits on an exhausted shadow descriptorConfigurations with shadow_mode descriptorsExpect previously allowed requests to be limited; a runtime guard reverts it
On-demand VHDS no longer recreates the stream after resolving a virtual hoston_demand filter usersFilters before it are no longer invoked twice; a runtime guard reverts it

The MCP router change is the one to read twice. A single router can aggregate backends of mixed trust, and forwarding the client's bearer token to each of them is a token-reuse problem; the Model Context Protocol asks for audience-bound tokens rather than passthrough. The new default is the safe one, and restoring forward-everything per backend should be a conscious exception.

Minor changes that break log parsers and dashboards

Three access log changes can break downstream consumers. Integer-valued substitutions such as bytes sent and durations are now rendered as exact integers in JSON logs rather than as doubles, so a value that used to appear as 1e+05 now appears as 100000; parsers accepting either form are unaffected, parsers relying on the exponent form are not. The COALESCE operator now returns the first present value even if it is empty. And the length limit on metadata operators now truncates only strings in typed output, so numbers and booleans keep their type. Removed runtime guards also make several behaviours permanent: HTTP/2 connections always fall back to the safe defaults of 1,024 concurrent streams, a 16 MiB stream window and a 24 MiB connection window when options are unset; the OAuth2 filter always strips its flow cookies before forwarding; and upstream header validation is always on. Debian bullseye packages are no longer published.

An AI protocol filter, for the curious

The AI Protocol Manager filter, still alpha, gains response-side token usage extraction for the OpenAI, Anthropic and Gemini dialects over both server-sent events and JSON, published as typed dynamic metadata, plus request-path statistics and a token estimation option that computes an input estimate from payload bytes. For a proxy that fronts several model providers this is the beginning of a vendor-neutral accounting layer, though the alpha label and the fail-open setting mean it is not yet a billing source of truth.

Upgrade checklist

  1. Build: migrate downstream builds to bzlmod with the Envoy registry before anything else; nothing else can be tested until the build works.
  2. Run the config dump and stats of a canary at 1.40.0 next to 1.39.x; check the worker count if you rely on container CPU detection.
  3. Test TLS handshakes upstream and downstream with the hybrid curve on; keep the pqc runtime flag ready to revert.
  4. Audit every mcp_router backend for the headers it now receives, and decide header_forwarding explicitly.
  5. Re-run log pipeline tests against JSON access logs with large durations and byte counts.
  6. Re-test shadow-mode local rate limits, and any tooling that calls the non-graceful drain endpoint.
  7. Only then evaluate HTTP/3 on downstream listeners, with UDP reachability verified end to end.

Sources and scope

Checked against these sources on 19 October 2026. Event: envoyproxy/envoy v1.40.0 release, 13 October 2026; recheck it before acting. Examples and figures are illustrative, not measurements.

Migrate builds to bzlmod first, test TLS with the hybrid post-quantum curve, decide mcp_router header forwarding explicitly, and re-test log parsers and drain tooling before enabling HTTP/3.