1.39.0 (Pending)
Incompatible behavior changes
Changes that are expected to cause an incompatibility if applicable; deployment changes are likely required
tls: The enforce_rsa_key_usage configuration option has been deprecated and ignored. Envoy now always enforces the
keyUsageextension in peer certificates. Configurations setting this option tofalsewill no longer have any effect and enforcement will be used.
Minor behavior changes
Changes that may cause incompatibilities for some users, but should not for most
dns: Runtime guard
envoy.reloadable_features.enable_new_dns_implementationis now enabled by default. This activates the new DNS implementation, a merged implementation of strict and logical DNS clusters. It can be temporarily reverted by setting the runtime guard tofalse.golang: Reduced the per-cgo-call mutex acquisition on the Golang HTTP filter by making the
has_destroyed_flag astd::atomic<bool>. CAPI methods whose only Envoy-side work is Filter-owned or runs on the worker thread (setHeader,removeHeader,setTrailer,removeTrailer,addData,injectData,continueStatus,sendLocalReply,setBufferHelper,copyBuffer,drainBuffer,setUpstreamOverrideHost,clearRouteCache,setDynamicMetadata,setStringFilterState) no longer take the mutex, eliminating an uncontended atomic compare-and-swap pair on every such call. The mutex is retained on the CAPI methods that inline-dereference Envoy-stream-owned objects from off-thread (getHeader,copyHeaders,copyTrailers,getIntegerValue,setDrainConnectionUponCompletion) where it serialises againstonDestroyto prevent the worker thread from freeing the underlying header map orStreamInfomid-access, and on the five methods that write to the per-requeststrValuescratch buffer (getStringValue,getDynamicMetadata,getStringFilterState,getStringProperty,getSecret).http2: The GOAWAY load shed point is fixed to use a graceful two-phase shutdown sequence, to avoid risk to client traffic. This behavioral change can be temporarily reverted by setting runtime guard
envoy.reloadable_features.http2_fix_goaway_loadshed_pointtofalse.load_balancer: The least request load balancer can now include pending requests (streams queued on a connection pool waiting for a connection to establish) in the per-host load value used for selection. This is disabled by default and can be enabled by setting runtime guard
envoy.reloadable_features.least_request_lb_count_pending_requeststotrue. Also adds a newcluster.<name>.endpoint.<addr>.rq_pending_activeper-endpoint gauge.router: The upstream transport failure reason (e.g. TLS certificate validation errors) is no longer included in the HTTP response body sent to downstream clients. It remains available in access logs via
%UPSTREAM_TRANSPORT_FAILURE_REASON%. This behavioral change can be temporarily reverted by setting runtime guardenvoy.reloadable_features.hide_transport_failure_reason_in_response_bodytofalse. This is being changed because in many cases the upstream failure details are inappropriate to send to the downstream client as it discloses too many internal details.stats: Optimized prometheus stats endpoint. Users should see a roughly 30-40% latency improvement in calls to the endpoint for cases where the scrape results in lots of cluster stats. There should be no visible changes to users, or incompatibilities.
tls:
SslSocketnow reportsECONNRESETasConnectionResetby reading the system error code from BoringSSL’s error queue, matchingRawBufferSocketbehavior. When a connection is closed withConnectionCloseType::AbortReset,SslSocketalso skips the TLSclose_notifyshutdown so the peer reliably observes a TCP RST instead of racing a graceful close against the reset. This behavioral change can be temporarily reverted by setting runtime guardenvoy.reloadable_features.ssl_socket_report_connection_resettofalse.
Bug fixes
Changes expected to improve the state of the world and are unlikely to have negative effects
build: Fixed
Illegal ambiguous matcherror when building contrib targets with--config=aws-lc-fipson aarch64 by restricting theusing_aws_lcbranch ofSELECTED_CONTRIB_EXTENSIONStolinux_x86_64. Mirrors the approach taken by #32382 forboringssl_fips.build: Fixed
Illegal ambiguous matcherror when building contrib targets with--config=boringssl-fipson aarch64 by restricting theusing_boringssl_fipsbranch ofSELECTED_CONTRIB_EXTENSIONStolinux_x86_64. Mirrors the approach taken by #44661 foraws-lc.dns_resolver: Fixed a UAF in the Hickory DNS resolver where the dispatcher lambda posted by the Rust-thread completion callback captured a raw pointer to the resolver. If the resolver was destroyed before the dispatcher drained the lambda, dereferencing the pointer was undefined behavior. The lambda now captures a
std::weak_ptrand locks it before touching the resolver.dns_resolver: Fixed a memory leak in the Hickory DNS resolver where
ActiveDnsQuery::cancel()did not free the pending query state or decrement thepending_resolutionsgauge. Cancelled queries now release their shell object, Rust-side query box, and gauge tick synchronously, matching the contract followed by the c-ares and Apple DNS resolvers.dns_resolver: Fixed macOS build failure (#45061) for the Hickory DNS resolver by linking Apple’s
SystemConfigurationframework. The framework is required by thesystem-configurationcrate thathickory-resolverpulls in via itssystem-configfeature.dynamic_modules: Fixed a bug where the HTTP filter per-route configuration and the upstream HTTP TCP bridge configuration did not handle the
google.protobuf.Structconfiguration message as the API definition requires. Both factories now serialize theStructto a JSON string and pass the string to the dynamic module side as the configuration, matching the behavior already in place for every other dynamic module extension factory.dynamic_modules: Fixed a crashing bug in the HTTP filter when a stream was already above the downstream write-buffer high watermark at filter-chain construction time. Downstream watermark callback registration is now deferred until the in-module filter has been constructed.
file_server: Fixed a use-after-free in the
file_serverHTTP filter when a request is cancelled (downstream RST, stream timeout, etc.) before the underlyingAsyncFileManager::statorreadcallback fires.FileStreamerpreviously captured[this]into the async-file callbacks, which left a dangling pointer if theFileStreamerwas destroyed while a stat or read was still in flight or already queued on the owner dispatcher. The callbacks now usecancelWrapped(source/common/common/cancel_wrapper.h): the in-flight file operation is aborted via the file-side cancel, and any callback already dispatched to the worker’s event loop short-circuits before dereferencing the freedFileStreamer.golang: Fixed a crash in the Golang HTTP filter introduced by #44503 where
continueStatusorsendLocalReplyinvoked synchronously from inside a GoOnHttpHeader/OnHttpDatacgo callback would re-enter the C++ state machine while the cgo frame was still on the stack, tripping theASSERT(filterState() == Processing*)at the top ofhandle*GolangStatusonce the cgo call returned. The inline-on-worker-thread optimization from #44503 is reverted for these two CAPI methods; both now always post to the dispatcher, matching the pre-#44503 behavior.http: Fixed a bug in the HTTP connection pool grid where, when starting with HTTP/2 (e.g., HTTP/3 is disabled or broken) and the TCP connection fails, a redundant second TCP connection attempt was scheduled instead of immediately propagating the failure. This behavior can be temporarily reverted by setting the runtime flag
envoy.reloadable_features.connectivity_grid_prevent_double_h2_scheduledtofalse.http: Fixed a bug where an upstream HTTP/2 or HTTP/3
RST_STREAM(NO_ERROR)received after a complete response would cause the response to be discarded and replaced with an error. This behavior is common with some gRPC clients and servers, but is often intermittent. This behavior can be temporarily reverted by setting the runtime flagenvoy.reloadable_features.http_preserve_rst_no_errortofalse.http: Fixed a re-entrancy bug in the connection pool where attaching a pending stream to a ready connection could recursively trigger connection allocation and ready callbacks if the stream was synchronously reset. This is resolved by removing the pending stream from the queue before calling its initialization/ready callback. This behavior can be temporarily reverted by setting the runtime flag
envoy.reloadable_features.conn_pool_fix_reentrancytofalse.http: Fixed a use-after-free and virtual method call crash in the connectivity grid during teardown when connection attempts are still active. This fix can be temporarily disabled by setting runtime feature
envoy.reloadable_features.conn_pool_grid_early_return_on_teardowntofalse.http2: Fix: CVE-2026-47774
HTTP/2 streams will now be reset if the stream violates the maximum header list size configured via
mutable_max_request_headers_kb. Note that this is different than the per header size specified bymax_header_field_size_kb. Uncompressed cookies now count towards this limit to protect Envoys against large uncompressed cookies causing excessive memory usage. Additionally, cookies now also count towardsmax_headers_countlimits. This behavior can be reverted by setting the runtime guardenvoy.reloadable_features.http2_include_cookies_in_limitsto false.load_report: Fixed a bug in load stats reporting where reports were dropped if only custom metrics or completed requests were present in a reporting interval. This behavioral change can be reverted by setting the runtime guard
envoy.reloadable_features.report_load_for_non_zero_statstofalse.mcp: Transitioned the JSON parser to complete parsing of the root object, removing the early-stopping optimization to mitigate JSON Parameter Pollution (JPP) vulnerabilities.
oauth2: Fixed a bug where HMAC verification may exposure a timing side channel that leaks information of HMAC secret validity.
oauth2: Fixed a crash in the OAuth2 filter where AES-CBC decryption of token cookies could spuriously succeed (~1/256) when the configured HMAC secret did not match the secret used to encrypt the cookie (for example after secret rotation, or when receiving legacy unencrypted tokens). The resulting binary “plaintext” was written back into the
Cookie:request header and tripped aHeaderStringvalidation assert. Such plaintexts are now rejected and the original cookie value is preserved, matching the behavior already documented for the explicit decryption-failure case.rbac: Fixed a bug in the mTLS Authenticated principal extension where if an invalid SAN matcher was configured, it would incorrectly match any certificate in the allowed trust chain. Known bad configurations are an invalid
OIDwhen using anOTHER_NAME, or specifying aStringMatcherwith an invalid configuration.router: Fixed a lifetime bug in dynamic forward proxy async host selection when the cluster is removed while lookup is still pending. Pending lookups are now cleaned up on DFP load balancer teardown, and the router no longer resumes async completion through a stale cluster reference.
spiffe_validator: Fixed a bug where if an invalid custom SAN matcher was configured it would later lead to a crash when validating a certificate.
tracing: Fixed Zipkin
timestamp_trace_idsto encode Unix epoch seconds in the high 32 bits of generated trace IDs, matching the documented[32-bit epoch seconds][32-bit random]format. Previously Envoy used monotonic clock seconds, so the trace ID prefix did not correspond to wall-clock time.vhds: Fixed a bug where VHDS using a static route configuration wasn’t sending VHDS subscriptions. It should now send subscriptions and also work on-demand.
wasm: Fixed a bug where Envoy did not recreate the Wasm VM when only environment_variables changed in
vm_config. The VM was previously reused from the cache because environment variables were not included in the vm_key computation.
New features
access_log: Added
%UPSTREAM_SERVER_NAME%access log formatter returning the SNI from the established upstream TLS connection.access_log: Supported the singleton stats scope in the stats access logger.
attributes: Added
upstream.server_nameCEL attribute returning the SNI from the established upstream TLS connection.circuit_breaker: Added support for configuring a budget_interval on the retry budget circuit breaker, allowing new requests to be considered for the duration of the interval when calculating the retry budget. Defaults to 0ms (preserving existing behavior).
composite: Added support for the inline matcher in the composite HTTP filter. Now users could specify the matcher inline in the filter configuration instead of using the ExtensionWithMatcher filter.
dynamic_modules: Added ABI primitives for publishing main-thread state out to worker threads on the cluster dynamic-module extension:
envoy_dynamic_module_callback_cluster_run_on_all_workers(with the matchingenvoy_dynamic_module_on_cluster_worker_eventhook) fans an event out to every registered worker;envoy_dynamic_module_callback_cluster_worker_slot_set/envoy_dynamic_module_callback_cluster_worker_slot_get(with the matchingenvoy_dynamic_module_on_cluster_worker_slot_data_destroycleanup hook) publish an opaque payload into a worker thread-local slot and read it back. The Rust SDK adds matchingCluster::on_worker_event,EnvoyCluster::run_on_all_workers, and anEnvoyClusterWorkerSlotExtextension trait with type-safeworker_slot_set<T>(Arc<T>)/worker_slot_get<T>() -> Option<Arc<T>>.dynamic_modules: Added
envoy_dynamic_module_callback_cluster_lb_context_get_filter_state_bytesandenvoy_dynamic_module_callback_cluster_lb_context_get_filter_state_typedABI callbacks so that a dynamic-module cluster’s load balancer can read filter state set by an upstream HTTP filter (or any other producer) when picking a host. The Rust SDK exposes these asClusterLbContext::get_filter_state_bytesandClusterLbContext::get_filter_state_typed.dynamic_modules: Added
envoy_dynamic_module_callback_http_set_dynamic_metadata_string_batchABI callback that sets multiple string-valued dynamic metadata entries under a single namespace in one call, resolving the namespace and merging into the metadata struct once instead of once per entry. The Rust SDK exposes this asEnvoyHttpFilter::set_dynamic_metadata_string_batch.dynamic_modules: Added
envoy_dynamic_module_callback_is_validation_modeABI callback that allows dynamic modules to check if the server is running in config validation mode.dynamic_modules: Added the
envoy_dynamic_module_callback_cluster_lb_context_get_host_statABI callback so custom cluster load balancers can read per-host counters and gauges at request time insideenvoy_dynamic_module_on_cluster_lb_choose_host. The Rust SDK exposes this asClusterLbContext::get_host_stat.gcp_authn: Added support to fetch and inject bound JWTs from the GCE Metadata Server. Configured via the
bound_jwtfield in the Audience proto.gcp_authn: Added support to fetch and inject unbound Access Tokens from the GCE Metadata Server. Configured via the
access_tokenfield in the Audience proto.http_inspector: Enabled Balsa parser for HTTP inspector by default. This behavior can be temporarily reverted by setting the runtime guard
envoy.reloadable_features.http_inspector_use_balsa_parsertofalse. This runtime guard will be removed in a future release of Envoy.http_inspector: Enabled Balsa parser for HTTP inspector by default. This behavior can be temporarily reverted by setting the runtime guard
envoy.reloadable_features.http_inspector_use_balsa_parsertofalse. This runtime guard will be removed in a future release of Envoy.jwt_authn: Added verification_status_header to the
ExtractOnlyWithoutValidationrequirement. When a JWT is present in the request but fails signature verification, the named request header (defaultx-jwt-signature-verified) is set tofalseso downstream filters (RBAC, ext_authz) can distinguish forwarded-but-unverified claims from validated ones. The header is not set on a successfully verified JWT or when no JWT is present. This behavior can be reverted by setting the runtime guardenvoy.reloadable_features.jwt_authn_add_verification_status_headertofalse.load_balancing: client_side_weighted_round_robin: implemented out-of-band ORCA load reporting via server-streaming gRPC (
xds.service.orca.v3.OpenRcaService.StreamCoreMetrics) when enable_oob_load_report is true. Cluster-scoped stats are emitted under thelb_orca_oob.prefix.logging: Added
%Nas a custom spdlog pattern flag that emits the Envoy version string. It can be used in the--log-formatCLI flag or the bootstrapapplication_log_config.log_formatto include the running version in every log line, e.g.--log-format "[%N][%l] %v".mcp: Added reject_duplicate_keys config option (defaulting to false) to reject requests that contain duplicate JSON keys at any nesting level.
mcp: Changed body size limit behavior when the request body exceeds the configured limit. In
PASS_THROUGHmode, the request is allowed through with anis_exceeding_limitmarker in the dynamic metadata. InREJECT_NO_MCPmode, the request is rejected with a400 Bad Requestif required fields are not found within the limit.mcp_router: Added lazy_initialization option to the MCP router filter. When enabled, the
initializeresponse is returned immediately without contacting backends. Each backend is initialized on-demand when a request first routes to it, avoiding slow or misbehaving backends from blocking client initialization.mysql_proxy: Added SSL termination support to the MySQL proxy filter with RSA-mediated
caching_sha2_passwordauthentication. The filter can now terminate downstream TLS connections using the starttls transport socket and transparently mediate MySQL 8.0+caching_sha2_passwordfull authentication by performing RSA public key exchange on behalf of the client. Added a new downstream_ssl config option withDISABLE,REQUIRE, andALLOWmodes.network_ext_proc: Added
close_stream_to_ext_proc_serverto ProcessingResponse to allow the external processor to request closing the gRPC stream early, causing subsequent data to bypass the networkext_procfilter.network_ext_proc: Added support for receiving untyped dynamic metadata from the external processing server. Configured via receiving_namespaces.
quic: Added support for TLS session ticket resumption in QUIC using configured session ticket keys from session_ticket_keys. This enables faster reconnection across server instances by allowing clients to resume TLS sessions without full handshakes. The feature is disabled by default and can be enabled by setting runtime guard
envoy.reloadable_features.quic_session_ticket_supporttotrue.ratelimit: Make namespace for storing rate limit service response metadata configurable.
resource_monitors: Overload manager fixed heap resource monitor now supports max_heap_size_bytes_runtime for runtime-overridable max heap size (e.g. RTDS or
/runtime_modify).router: Added refresh_cluster_on_retry to retry policies so retry attempts can refresh the route-selected upstream cluster before being sent. This enables cross-cluster retries for dynamic cluster selection such as the matcher cluster specifier.
router: Added support for
refreshRouteClusteron weighted cluster routes. When a filter callsrefreshRouteCluster(), the weighted cluster entry will select a different cluster from the configured pool, avoiding previously-tried clusters within the same request. Once all clusters have been tried, the selection pool resets so that any cluster may be chosen again. This enables filters to implement per-attempt cluster failover across weighted clusters without replacing the entire route.set_metadata_filter: Added per-route configuration support to the
set_metadataHTTP filter.stat_sinks: Added max_data_points_per_request configuration to the OpenTelemetry stat sink to chunk metric export requests.
stat_sinks: Added a new WASM stats filter contrib extension (
envoy.stat_sinks.wasm_filter) that acts as programmable middleware between the metrics snapshot and any inner stats sink. A user-supplied WASM plugin can: filter metrics by index, inject global tags from node metadata (stats_filter_set_global_tags), rename metrics (stats_filter_set_name_overrides), inject synthetic counters/gauges (stats_filter_inject_metrics), and filter histograms (stats_filter_get_histograms). This enables moving centralized metric processing logic (tag enrichment, name rewriting, custom metric injection) into the proxy itself. Configured via WasmFilterStatsSinkConfig.stats: Added observability_name to Endpoint so endpoints can override the observability name used in per-endpoint stats. This allows clusters with duplicate endpoint addresses to expose distinct per-endpoint stats.
tcp_proxy: Added check_drain_close to the TCP proxy filter to close downstream connections with
FlushWritewhen the drain manager requests drain close during downstream read or write handling.tcp_proxy: Added
envoy.reloadable_features.tcp_proxy_delay_route_selectionto delay selecting a route until just before the upstream connection is established. The selection moment depends on the value of upstream_connect_mode.tls: Added substitution commands
%DOWNSTREAM_TLS_GROUP%and%UPSTREAM_TLS_GROUP%. The TLS group may be used to discern if a TLS connection used a post quantum safe key exchange (e.g. X25519MLKEM768).