# 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.

```cpp
// 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.cc` handleDynamicMetadata() line 1636-1643
- `source/extensions/filters/http/ext_proc/ext_proc.h` line 303-304, 396, 686
