Where
-Infinity
0
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy normally matches the raw request path, while servlet backends such as Apache Tomcat strip semicolon matrix parameters from each path segment before resolving the resource. Envoy's ignorepathparametersinpathmatching option instead truncates at the first semicolon and still does not match per-segment backend behavior. A remote client can use a parameterized protected segment, or a parameter on an earlier segment, to make Envoy select an unprotected fallback while the backend resolves the protected resource. The relevant scope boundary is that the bypass requires both a path-based Envoy decision and a backend that strips semicolon parameters per segment. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:L/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, When ignorepathparametersinpathmatching is enabled, Envoy's router strips the semicolon suffix before matching but the RBAC urlpath matcher evaluates the raw path. A downstream request such as /admin;x can therefore miss a DENY rule for /admin while the router still selects the protected /admin backend. The inconsistent canonicalization allows an unauthenticated client to bypass path-based authorization. The relevant scope boundary is that the route option and a path-based RBAC rule must both be present, and the protected route must match after stripping. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
5.3
AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's URL normalization does not recognize dot and dotdot path segments when they carry semicolon parameters. A request such as /user/..;foo=bar/admin is therefore not canonicalized to /admin even when path normalization is enabled. If an upstream interprets the segment according to RFC 3986 while Envoy applies routing or RBAC to the uncollapsed path, a remote client can cause path confusion and bypass path-based security policy. The relevant scope boundary is that the security consequence depends on a downstream/upstream path interpretation mismatch or a path-based Envoy decision. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.4
XSS
AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's /stats?format=html admin endpoint uses StatsHtmlRender, which sanitizes string statistic values but emits statistic names without HTML encoding. A data-plane component such as grpcstats with statsforallmethods enabled can incorporate attacker-controlled path segments into cached dynamic statistic names. When an operator views the HTML stats page, the stored name can execute script with the admin interface's origin and issue privileged same-origin requests. The relevant scope boundary is that the admin interface must be browser-accessible and an enabled component must persist attacker-influenced text in statistic names. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
Use After Free
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's HttpDatagramHandler caches the current RequestDecoder when Capsule Protocol is enabled. Stream recreation, including an internal redirect, replaces the ActiveStream and updates EnvoyQuicServerStream but does not update the handler's cached pointer. A subsequent HTTP/3 datagram can call decodeData through the freed decoder, causing invalid virtual dispatch and a process crash. The relevant scope boundary is that hTTP/3 datagrams and Capsule Protocol must be enabled, and the request must enter a stream-recreation path such as an internal redirect. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy copies every decoded HTTP/2 Host header value before discarding it when :authority is already present. The discarded value bypasses saveHeader, so its bytes and count are not charged against request header limits. An unauthenticated client can use HPACK indexing to submit many references to a large Host value across a bounded number of streams, forcing extreme header-copy allocation and causing the proxy to be out-of-memory killed. The relevant scope boundary is that the demonstrated amplification uses HTTP/2 HPACK and the duplicate Host discard behavior. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
Input Validation, Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's extauthz filter assumes that a request contains a :path pseudoheader when applying queryparameterstoset or queryparameterstoremove from an authorization response. A path-less CONNECT request makes requestheaders->Path() return null, and Filter::onComplete dereferences that pointer while parsing the query string. An unauthenticated downstream client can crash the Envoy process when the filter and authorization response use query-parameter mutation. The relevant scope boundary is that the deployment must accept path-less CONNECT and configure extauthz query-parameter mutation. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
5.9
Null Pointer Dereference
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's ProdClusterManagerFactory::allocateConnPool dereferences transportsocketoptions while selecting an HTTP/3 connection pool without first checking whether the pointer is null. LoadBalancerContext implementations used by synthetic, mirror, health-check, and async-client calls can return no transport-socket options. With autoconfig and HTTP/3 enabled, routine traffic reaching one of those contexts can crash an Envoy worker. The relevant scope boundary is that the affected branch requires HTTP/3 in the protocol set and a context that supplies no transport-socket options. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
5.3
AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's Utility::copyInternetAddressAndPort and QUIC client-address paths reconstruct scoped IPv6 addresses through addressAsString and Ipv6Instance. The string includes a percent scope identifier that inetpton cannot parse, causing an exception or abort. Kernel-provided scoped IPv6 destinations in ORIGINALDST transparent-proxy deployments, and affected QUIC connection paths, can therefore terminate the process. The relevant scope boundary is that the HTTP usehttpheader override rejects scoped addresses earlier; the advisory's crash path requires a kernel-provided original destination or the affected QUIC path. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
Input Validation, Use After Free
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's optional oghttp2 upstream HTTP/2 codec accepts a response trailer HEADERS frame without ENDSTREAM. Envoy completes and deferred-deletes the ActiveRequest while oghttp2 keeps the stream open, leaving ClientStreamImpl with a dangling responsedecoder reference. A later frame on the stream can dispatch through the freed object and crash the process. The relevant scope boundary is that the default nghttp2 codec rejects the malformed trailers, and the trigger is upstream-only with oghttp2 enabled. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
Input Validation
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy HTTP RBAC accepts RFC-valid opaque header bytes but evaluates saferegex values with RE2's UTF-8 subject semantics. A downstream client can preserve a prohibited marker and add an unrelated obs-text octet, causing RE2::FullMatch to return false and a negative RBAC policy to treat the invalid subject as an ordinary no-match. A byte-oriented route matcher can still observe the marker, allowing the request to reach a route intended to be denied. The relevant scope boundary is that plain positive ALLOW regexes normally fail closed, and exact, prefix, suffix, and contains matchers are not shown to have this subject-domain failure. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy forwards data for a configured non-WebSocket HTTP upgrade before the upstream accepts the upgrade. An unauthenticated HTTP/2 client can place a complete HTTP/1.1 request in extended CONNECT data; Envoy downgrades the request, writes the data unframed to a keep-alive HTTP/1.1 upstream, and returns the socket to the shared pool while the smuggled response remains queued. A different downstream client can then receive the attacker's response. The relevant scope boundary is that webSocket upgrades, plain CONNECT, disabled backend keep-alive, per-downstream pools, and maxrequestsperconnection set to 1 are not affected by the demonstrated path. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
5.9
Use After Free
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.36.10, 1.37.6, 1.38.4, and 1.39.1, Envoy's HTTP external-authorization client can retain a stale request callback after a request is rejected. When RawHttpClientImpl::onSuccess later processes the authorization response, it can invoke callbacks after the callback owner has been destroyed, causing a use-after-free and process crash under production traffic. The relevant scope boundary is that the vulnerable path uses the HTTP extauthz client; the advisory does not establish the same trigger for unrelated filters. This issue is fixed in versions 1.36.10, 1.37.6, 1.38.4, and 1.39.1.

First published (updated )
Severity
5.9
Use After Free
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.37.0 until 1.37.5 and 1.38.3, the HTTP OAuth2 filter (envoy.filters.http.oauth2) can leave an in-flight async token exchange attached to a downstream stream that has already been torn down. A late AsyncClient completion can still invoke OAuth2Filter methods that use StreamDecoderFilterCallbacks after that object’s lifetime has ended, causing undefined behavior, worker crashes (availability loss), and use-after-free / invalid-vptr failures under AddressSanitizer. This is a memory-safety / lifetime issue in the data plane, not a trivial config bug. Remote code execution is not claimed here; the primary demonstrated impact is DoS via crash and UB; any further impact would be deployment- and allocator-dependent. This vulnerability is fixed in 1.37.5 and 1.38.3.

First published (updated )
Severity
7.5
Null Pointer Dereference
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.37.0 until 1.37.5 and 1.38.3, when the %REQUESTEDSERVERNAME(X:Y)% is used in log format and host related options is specified, like HOSTFIRST, SNIFIRST, it's possible to crash Envoy when the specified host header is missing in the request headers. This vulnerability is fixed in 1.37.5 and 1.38.3.

First published (updated )
Severity
5.9
Use After Free
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.36.0 until 1.36.9, 1.37.5, and 1.38.3, a Use-After-Free (UAF) vulnerability leading to a sudden segmentation fault exists in Envoy's extauthz HTTP filter when processing per-route authorization overrides concurrently with rapid downstream client disconnects. During standard request lifecycles, Envoy instantiates the extauthz filter with a foundational authorization client object (client). If a matched route dictates a dynamic per-route HTTP or gRPC authorization service override, the filter generates a localized client. In the vulnerable implementation, this transient client aggressively overwrote the default client unique pointer by executing client = std::move(perrouteclient). When a client rapidly establishes and subsequently tears down a stream (such as rapidly refreshing a protected WebSocket endpoint), the downstream triggers the ConnectionManagerImpl::doDeferredStreamDestroy() -> ActiveStream::onResetStream() lifecycle. Envoy immediately sequences Filter::onDestroy() in an attempt to securely abort dispatched asynchronous authorization check transactions via client->cancel(). By destructing the default client abruptly during initiateCall, a memory lifecycle misalignment occurs within the async client manager. The stream teardown fails to reliably track and cancel the dynamically bound asynchronous authorization tasks, orchestrating a sequence where a late asynchronous callback from the network evaluates against a heavily destroyed ActiveStream validation span, generating a UAF process crash. This vulnerability is fixed in 1.36.9, 1.37.5, and 1.38.3.

First published (updated )
Severity
4.8
AV:A/AC:L/PR:H/UI:N/S:C/C:N/I:L/A:L

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.34.0 until 1.35.13, 1.36.9, 1.37.5, and 1.38.3, PROXY Protocol v2 header generator emits TLVs beyond the maximum length of 65535 bytes, causing a mismatch between bytes written and the length field in the header. This can result in smuggled bytes on the upstream request. This vulnerability is fixed in 1.35.13, 1.36.9, 1.37.5, and 1.38.3.

First published (updated )
Severity
6.5
Use After Free
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.34.0 until 1.35.13, 1.36.9, 1.37.5, and 1.38.3, Envoy crashes if an extproc server sends a single gRPC message containing multiple, specially crafted ProcessingResponse messages. This can occur when the first response in the batch causes the gRPC stream object to be destroyed, leading to a use-after-free error when Envoy attempts to process subsequent responses in the same gRPC message. This vulnerability is fixed in 1.35.13, 1.36.9, 1.37.5, and 1.38.3.

First published (updated )
Severity
7.5
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.34.0 until 1.35.13, 1.36.9, 1.37.5, and 1.38.3, a vulnerability exists in Envoy's TCP StatsD sink (TcpStatsdSink), where the thread-local flusher buffer can be overflowed by exceptionally long statistic names (e.g., >16KiB). During formatting, TcpStatsdSink reserves a single contiguous memory slice of 16KiB (FLUSHSLICESIZEBYTES). If formatting a single metric exceeds the remaining capacity, the flusher initiates a buffer rotation but incorrectly continues to allocate another fixed 16KiB slice. If an attacker can trigger a statistic name longer than 16KiB—for example, by sending an HTTP or gRPC request with an extremely long request path (:path) that is recorded by the grpcstats filter configured with statsforallmethods: true—the flusher will attempt to copy the metric name using memcpy operations beyond the allocated heap buffer boundaries. This leads to a heap write overflow, which can cause immediate denial-of-service (process crash) or potential remote code execution (RCE). This vulnerability is fixed in 1.35.13, 1.36.9, 1.37.5, and 1.38.3.

First published (updated )
Severity
7.5
Null Pointer Dereference
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.26.0 until 1.35.13, 1.36.9, 1.37.5, and 1.38.3, the envoy.filters.http.grpcstats filter crashes (null pointer dereference / segfault) when a Connect protocol request (Content-Type: application/connect+proto or application/connect+json) hits a directresponse route. A single unauthenticated HTTP request crashes the Envoy process. This vulnerability is fixed in 1.35.13, 1.36.9, 1.37.5, and 1.38.3.

First published (updated )
Severity
7.5
Null Pointer Dereference
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.18.0 until 1.35.13, 1.36.9, 1.37.5, and 1.38.3, the router filter contains a null pointer dereference vulnerability when handling HTTP 303 (See Other) internal redirects for body-less non-GET/HEAD requests. When a POST, PUT, DELETE, or PATCH request without a body is sent to a route configured with internal redirect policy that includes 303 in redirectresponsecodes, and the upstream responds with HTTP 303, the redirect handling code attempts to drain a request body buffer that was never allocated. This results in a segmentation fault that crashes the entire Envoy process. When route configured with internalredirectpolicy including 303 in redirectresponsecodes and upstream must return HTTP 303 response, an unauthenticated attacker can exploit this to cause complete denial of service, terminating all active connections. This vulnerability is fixed in 1.35.13, 1.36.9, 1.37.5, and 1.38.3.

First published (updated )
Severity
7.5
AV:N/AC:H/PR:N/UI:N/S:C/C:L/I:H/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.35.11, 1.36.7, 1.37.3, and 1.38.1, Envoy can translate a downstream HTTP/3 request that is complete at the transport layer (HEADERS with FIN / headers-only close) but still carries a nonzero Content-Length into a complete upstream HTTP/1 request with unresolved body debt. In an HTTP/1 upstream deployment where the origin replies before reading the declared body and keeps the connection reusable, the beginning of the next Envoy-generated upstream request can be consumed as the first request's body. The remaining bytes are then parsed by the origin as a new HTTP/1 request. This was reproduced as a route-bypass/desync: direct /pwn was denied by Envoy, but the second downstream H3 stream received the response for backend-parsed GET /pwn HTTP/1.1. This vulnerability is fixed in 1.35.11, 1.36.7, 1.37.3, and 1.38.1.

First published (updated )
Severity
7.5
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.35.11, 1.36.7, 1.37.3, and 1.38.1, in cases where UDP DNS filter is configured with local resolution containing a name with the length of 255 octets or remote resolution for a name of 255 octets long can complete successfully, a query with such name will result in abnormal process termination. The abnormal process termination is triggered by an invalid runtime precondition that the query name is strictly less than 255 octets, contradicting DNS specification rfc1035#section-2.3.4 that the name can be 255 or less octets. This vulnerability is fixed in 1.35.11, 1.36.7, 1.37.3, and 1.38.1.

First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. From 1.23.0 until 1.35.11, 1.36.7, 1.37.3, and 1.38.1, a vulnerability has been identified in Envoy's zstd decompressor implementation (ZstdDecompressorImpl). When zstd decompression is enabled, processing a specially crafted, highly compressed zstd payload can lead to massive memory allocation. An attacker can exploit this to cause severe memory exhaustion, potentially resulting in an Out-Of-Memory (OOM) kill and Denial of Service (DoS) for the Envoy proxy. This vulnerability is fixed in 1.35.11, 1.36.7, 1.37.3, and 1.38.1.

First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.35.11, 1.36.7, 1.37.3, and 1.38.1, destructor of JSON Object results in stack overflow when deeply O(100K) nested objects are present. This vulnerability is fixed in 1.35.11, 1.36.7, 1.37.3, and 1.38.1.

First published (updated )
Severity
4.4
AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.35.11, 1.36.7, 1.37.3, and 1.38.1, a structural flaw was identified in DefaultCertValidator::verifySubjectAltName where the extracted DNS SAN string is cast to a C-style string using .cstr() before being passed to the Utility::dnsNameMatch() algorithm. If the attacker serves a certificate with a dNSName SAN containing an embedded NUL byte, the helper Utility::generalNameAsString captures the complete string including the NUL. However, when .cstr() evaluates it, implicit conversion to absl::stringview inside dnsNameMatch relies on strlen(), prematurely truncating the evaluation context. Envoy evaluates trucated string against the exact required configsan match and returns true, thereby successfully validating the string with the Nul byte for an upstream routing. This vulnerability is fixed in 1.35.11, 1.36.7, 1.37.3, and 1.38.1.

First published (updated )
Severity
6.8
AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N

Envoy is an open source edge and service proxy designed for cloud-native applications. Prior to 1.35.11, 1.36.7, 1.37.3, and 1.38.1, the OAuth2 HTTP filter's encrypt()/decrypt() functions use AES-256-CBC without an authentication tag (no HMAC, no AEAD). The /callback endpoint returns HTTP 302 on successful decryption and HTTP 401 on padding failure, creating a padding oracle. An attacker who obtains the encrypted CodeVerifier cookie can recover the plaintext PKCE codeverifier in ~6,200 requests (~100 seconds), then exchange it with a stolen authorization code to obtain the victim's access token. This vulnerability is fixed in 1.35.11, 1.36.7, 1.37.3, and 1.38.1.

First published (updated )
Severity
7.5
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

A denial-of-service vulnerability was found in Envoy's HTTP/2 implementation. The attack chains two techniques: an HPACK compression bomb that exploits header compression to amplify a single byte on the wire into a full header allocation on the server (repeated thousands of times per request), and a Slowloris-style hold using a zero-byte HTTP/2 flow-control window that prevents the server from ever freeing the allocated memory.

A remote attacker can exploit this in Envoy's default HTTP/2 configuration to consume and hold large amounts of server memory (up to 32GB in approximately 20 seconds), rendering the server inaccessible.

This vulnerability exists in each server's default HTTP/2 configuration and requires no authentication to exploit.

External Reference: https://blog.calif.io/p/codex-discovered-a-hidden-http2-bomb

1 / 2
Source: Red Hat
First published (updated )
Severity
7.5
Use After Free
AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:H

Summary

At the rate limit filter, if we enabled the response phase limit with applyonstreamdone in the rate limit configuration and the response phase limit request fails directly, it may crash Envoy.

Details

When both the request phase limit and response phase limit are enabled, the safe gRPC client instance will be re-used for both the request phase request and response phase request.

But after the request phase request is done, the inner state of the request phase limit request in gRPC client is not cleaned up. When we send the second limit request at response phase, and the second limit request fails directly, we may access the previous request's inner state and result in crash.

PoC

This need to mock the network failure. But we have reproduced by unit test locally.

Impact

This only happens when both the request phase limit and response phase limit are enabled in the rate limit filter, and requires the request to rate limit service fails directly (For example, if from Envoy's perspective, no healthy endpoint for rate limit service may result the request fails directly). That's say, not easy to trigger this.

To workaround

This could be worked around by splitting the rate limit filter. That is, if there is a rate limit filter that contains normal rate limit configuration (request phase limit, without applyonstreamdone) and also rate limit configuration with applyonstreamdone (response phase limit). Splitting them into two rate limit filters and ensure one filter only contains normal rate limit configuration (without applyonstreamdone), and one only contains rate limit configuration with applyonstreamdone could avoid this problem.

Credit

Mandar Jog (mandarjog@gmail.com)

1 / 2
Source: GitHub
First published (updated )
Severity
5.9
Use After Free
AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H

Note: This vulnerability was originally reported to the Google OSS VRP (Issue ID: 477542544). The Google Security Team requested that I coordinate directly with the Envoy maintainers for triage and remediation. I am submitting this report here to facilitate that process.

Technical Details I have identified a logic vulnerability in Envoy's HTTP connection manager (FilterManager) that allows for Zombie Stream Filter Execution. This issue creates a "Use-After-Free" (UAF) or state-corruption window where filter callbacks are invoked on an HTTP stream that has already been logically reset and cleaned up.

Mechanism: The vulnerability resides in source/common/http/filtermanager.cc within the FilterManager::decodeData method.

When an HTTP/2 stream encounters a reset condition (e.g., StreamIdleTimeout, OverloadManager limits, or a local reset triggered by a filter), Envoy calls onResetStream. This method: 1. Sets the internal state state.sawdownstreamreset = true. 2. Invokes onDestroy() on all filters in the chain (allowing them to release resources/pointers). 3. Schedules the ActiveStream object for deferred deletion (cleanup happens later in the event loop).

The Flaw: The ActiveStream object remains valid in memory during the deferred deletion window. If a DATA frame arrives on this stream immediately after the reset (e.g., in the same packet processing cycle), the HTTP/2 codec invokes ActiveStream::decodeData, which cascades to FilterManager::decodeData.

FilterManager::decodeData fails to check the sawdownstreamreset flag. It iterates over the decoderfilters list and invokes decodeData() on filters that have already received onDestroy().

Root Cause Code Location: File: source/common/http/filtermanager.cc Function: FilterManager::decodeData

cpp void FilterManager::decodeData(...) { if (stopDecoderFilterChain()) { return; }

// Vulnerability: Missing check for state.sawdownstreamreset // Execution proceeds into the loop even if the stream is logically dead.

auto trailersaddedentry = decoderfilters.end(); for (; entry != decoderfilters.end(); entry++) { // ... calls (entry)->handle->decodeData(data) on destroyed filters ... } }

Suggested Fix: Add an explicit state check at the beginning of FilterManager::decodeData.

cpp // Prevent execution on streams that have been reset but not yet destroyed. if (state.sawdownstreamreset) { return; }

---

Impact Analysis

Who can exploit this: Any remote attacker capable of establishing an HTTP/2 or HTTP/3 connection. No privileges/authentication required.

Impact & Gain: 1. Memory Corruption & Potential Remote Code Execution: While the immediate symptom is a crash (DoS), the underlying primitive is a Use-After-Free (CWE-416). Mechanism: When onDestroy() is called on filters (e.g., Lua, Wasm, or complex native filters), they release internal structures and invalidate pointers. Exploitation: By forcing decodeData() to execute on these now-freed objects, an attacker triggers undefined behavior. In a heap-groomed environment, an attacker could potentially replace the freed filter object with a malicious payload before the "Zombie" decodeData call occurs. This would allow for vtable hijacking or arbitrary write-what-where primitives, leading to Remote Code Execution (RCE). Risk Amplification: This is particularly dangerous for Envoy deployments using memory-unsafe extensions or third-party filters (C++ extensions), where onDestroy logic is relied upon for safety.

2. Security Control Bypass: The vulnerability defeats Envoy's "Fail-Closed" security architecture. Scenario: If a stream is reset due to a security violation (e.g., StreamIdleTimeout, OverloadManager rejection, or WAF triggering), this vulnerability allows the attacker to bypass the termination. Result: The attacker can force the processing of "Data" frames on a connection that the security policy explicitly attempted to close, allowing malicious payloads to reach deeper into the filter chain or backend services despite the rejection.

---

Proof of Concept (Unit Test)

Description: The attached C++ unit test (zombiestreampoctest.cc) deterministically reproduces the vulnerability. It creates a stream, manually triggers a reset (simulating an Overload), and then immediately injects a DATA frame. The test asserts that the filter's decodeData callback is invoked on the reset stream.

cpp #include "test/common/http/connmanagerimpltestbase.h" #include "gmock/gmock.h" #include "gtest/gtest.h"

using testing::; using testing::Invoke; using testing::NiceMock; using testing::Return;

namespace Envoy { namespace Http {

/ Proof of Concept for "Zombie Stream Filter Execution" (HTTP/2 Reset Re-entrancy) Logic flow: 1. Open a stream with HEADERS. 2. Force a stream reset (simulating an Overload or Timeout). 3. Immediately inject DATA into the stream. 4. ASSERT that the filter's decodeData is called despite the stream being reset. / class ZombieStreamPocTest : public HttpConnectionManagerImplTest { };

TESTF(ZombieStreamPocTest, ReproducedZombieFilterExecution) { setup(SetupOpts().setTracing(false));

// 1. Setup a mock filter std::sharedptr<MockStreamDecoderFilter> filter(new NiceMock<MockStreamDecoderFilter>()); // Vuln confirmation: // We expect decodeData to be called on this filter even though the stream is reset. // In a secure/patched implementation, this EXPECTCALL should fail (Times(0)). EXPECTCALL(filter, decodeData(, )) .Times(1) .WillOnce(Invoke(& -> FilterDataStatus { ENVOYLOGMISC(error, "!!! VULNERABILITY REPRODUCED: decodeData called on a reset stream !!!"); return FilterDataStatus::Continue; }));

EXPECTCALL(filter, decodeHeaders(, false)) .WillOnce(Return(FilterHeadersStatus::StopIteration));

// Register the filter EXPECTCALL(filterfactory, createFilterChain()) .WillOnce(Invoke(& -> bool { auto factory = createDecoderFilterFactoryCb(filter); callbacks.setFilterConfigName("vulnerablefilter"); factory(callbacks); return true; }));

// 2. Start the stream EXPECTCALL(codec, dispatch()) .WillOnce(Invoke(& -> Http::Status { decoder = &connmanager->newStream(responseencoder); RequestHeaderMapPtr headers{new TestRequestHeaderMapImpl{ {":authority", "host"}, {":path", "/"}, {":method", "POST"}}}; decoder->decodeHeaders(std::move(headers), false); return Http::okStatus(); }));

// Dispatch headers Buffer::OwnedImpl headerbuffer("headers"); connmanager->onData(headerbuffer, false);

// 3. Trigger a Reset on the ActiveStream // This simulates Envoy terminating the stream due to an external event (Overload, Timeout). auto activestream = dynamiccast<ConnectionManagerImpl::ActiveStream>(decoder); // This sets state.sawdownstreamreset = true and triggers filter->onDestroy() activestream->onResetStream(StreamResetReason::LocalReset, "simulatedoverload");

// 4. Attack: Send DATA to the "Zombie" stream // The ActiveStream object is still alive in the deferred delete list. Buffer::OwnedImpl maliciouspayload("attackerdata"); // This call reaches the filter because FilterManager::decodeData misses the check! activestream->decodeData(maliciouspayload, false); }

} // namespace Http } // namespace Envoy

1 / 2
Source: GitHub
First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203