CVE-2026-26311: 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). 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
ActiveStreamobject 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
void FilterManager::decodeData(...) {
if (stopDecoderFilterChain()) { return; }
// Vulnerability: Missing check for state_.saw_downstream_reset_
// Execution proceeds into the loop even if the stream is logically dead.
auto trailers_added_entry = decoder_filters_.end();
for (; entry != decoder_filters_.end(); entry++) {
// ... calls (*entry)->handle_->decodeData(data) on destroyed filters ...
}
}
Suggested Fix:
Add an explicit state check at the beginning of FilterManager::decodeData.
// Prevent execution on streams that have been reset but not yet destroyed.
if (state_.saw_downstream_reset_) {
return;
}
References
Code Behaviors & Features
Detect and mitigate CVE-2026-26311 with GitLab Dependency Scanning
Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Dependency Scanning using SBOM also detects vulnerabilities from proprietary advisories that this site does not include. Learn more about Dependency Scanning using SBOM →