GHSA-84xm-r438-86px: Envoy: HTTP - filter chain execution on reset streams causing UAF crash
**Note:**
This vulnerability was originally reported to the Google OSS VRP (Issue ID: [477542544](https://issuetracker.google.com/issues/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/filter_manager.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:Sets the internal state `state_.saw_downstream_reset_ = true`.Invokes `onDestroy()` on all filters in the chain (allowing them to release resources/pointers).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 `saw_downstream_reset_` flag**. It iterates over the `decoder_filters_` list and invokes `decodeData()` on filters that have already received `onDestroy()`.**Root Cause Code Location:**
File: `source/common/http/filter_manager.cc`
Function: `FilterManager::decodeData`**Suggested Fix:**
Add an explicit state check at the beginning of `FilterManager::decodeData`.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 (`zombie_stream_poc_test.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.
CVSS v3.1: 5.9