2.7 KiB
UNDF: UNDF-2026-000000390
envoy-0001: CWE-407 — Linear namespace membership scan on every ext_proc response, per-request
Severity: HIGH
Repository
github.com/envoyproxy/envoy Commit: a2fe7fb
File
source/extensions/filters/http/ext_proc/ext_proc.cc
Defective Lines
1636: auto receiving_namespaces = state.untypedReceivingMetadataNamespaces();
1637: for (const auto& context_key : response_metadata) { // outer: O(M) metadata keys
1638: bool found_allowed_namespace = false;
1639: if (auto metadata_it =
1640: std::find(receiving_namespaces.begin(), // inner: O(N) linear scan
1641: receiving_namespaces.end(),
1642: context_key.first);
1643: metadata_it != receiving_namespaces.end()) {
Type of receiving_namespaces
std::vector<std::string> — declared at ext_proc.h:396 and ext_proc.h:686.
untypedReceivingMetadataNamespaces() returns a const std::vector<std::string>&.
Complexity
O(M × N) per HTTP request that triggers ext_proc dynamic metadata processing, where:
- M = number of metadata keys in the ext_proc gRPC response
- N = number of configured receiving namespaces
This executes on the request data plane hot path inside handleDynamicMetadata(),
called from processResponse() for every ext_proc filter response.
Impact
At M=10 metadata keys and N=50 configured receiving namespaces, each ext_proc
response triggers 500 string comparisons. At 10,000 RPS this is 5,000,000 string
comparisons per second in a single worker thread. Latency spikes scale with N.
The receiving_namespaces vector is rebuilt from config on every call via
state.untypedReceivingMetadataNamespaces() (defensive copy at line 1636).
Fix
Replace std::vector<std::string> with absl::flat_hash_set<std::string> for the
receiving namespaces collection. Build once at filter config parse time; O(1)
amortized lookup per metadata key.
// In ExternalProcessorConfig (ext_proc.h):
// Before:
const std::vector<std::string> untyped_receiving_namespaces_;
// After:
const absl::flat_hash_set<std::string> untyped_receiving_namespaces_;
// In handleDynamicMetadata (ext_proc.cc):
// Before:
if (auto metadata_it =
std::find(receiving_namespaces.begin(), receiving_namespaces.end(), context_key.first);
metadata_it != receiving_namespaces.end()) {
// After:
if (receiving_namespaces.contains(context_key.first)) {
References
- CWE-407: Inefficient Algorithmic Complexity
source/extensions/filters/http/ext_proc/ext_proc.cchandleDynamicMetadata() line 1636-1643source/extensions/filters/http/ext_proc/ext_proc.hline 303-304, 396, 686