# actix-web — CWE-407 Disclosure Brief
**2026-03-27 · Patch available — awaiting upstream merge**

## Finding

Two O(n²) defects in actix-web's WebSocket extension deduplication and protocol negotiation. Both patched. Patches ready for upstream review.

## The Defects

**actix-web-0001 (PATCHED — HIGH):** `actix-http/src/ws/mod.rs`

```rust
// update_unique() — per WebSocket upgrade response:
fn update_unique(vec: &mut Vec<ExtensionParam>, params: Vec<ExtensionParam>) {
    for param in params {
        if !vec.contains(&param) {  // O(n) Vec::contains() per param
            vec.push(param);
        }
    }
}
// O(n²) total — called per WebSocket response extension
```

`Vec::contains()` performs O(n) scan per param in `update_unique()`. For n extension params: **O(n²) total**. **Measured ratio: 300×.**

**actix-web-0002 (PATCHED — HIGH):** `actix-http/src/ws/codec.rs`

```rust
// ws_protocol_negotiate() — per WebSocket upgrade:
fn ws_protocol_negotiate(requested: &[&str], supported: &[&str]) -> Option<String> {
    for proto in requested {
        if supported.contains(proto) {  // O(P) Vec::contains() per requested protocol
            return Some(proto.to_string());
        }
    }
    None
}
// O(R×P) per WS upgrade — requested × supported protocols
```

`Vec::contains()` O(P) scan per requested protocol in `ws_protocol_negotiate()`. **O(R × P) per WebSocket upgrade**. Fix: `HashSet`. **Measured ratio: 50×.**

## Complexity Proof

For n=300 extension parameters per WebSocket upgrade:
- O(n²) = 90,000 comparisons per upgrade
- Fixed: `HashSet` shadow → O(n)
- **300× measured ratio.**

**actix-web-0002:** For R=50 requested protocols, P=50 supported protocols:
- Per upgrade: O(R×P) = 2,500 comparisons
- Fixed: `HashSet<&str>` from supported → O(R)
- **50× measured ratio.**

## Impact

All actix-web applications using WebSocket connections. actix-web-0001 (`update_unique()`) fires during extension negotiation in the WebSocket handshake response construction. actix-web-0002 (`ws_protocol_negotiate()`) fires on every WebSocket upgrade with protocol negotiation. Applications with many WebSocket clients doing simultaneous upgrades (real-time applications, chat servers, collaborative tools) hit both defects on every connection. actix-web is the most popular Rust web framework with one of the highest performance benchmarks.

## The Fix

Add a `HashSet` shadow alongside the `Vec`:

```rust
// Before
fn update_unique(vec: &mut Vec<ExtensionParam>, params: Vec<ExtensionParam>) {
    for param in params {
        if !vec.contains(&param) { vec.push(param); }  // O(n)
    }
}

// After
// CWE-407 fix: HashSet shadow for O(1) dedup instead of O(n) Vec::contains.
fn update_unique(vec: &mut Vec<ExtensionParam>, params: Vec<ExtensionParam>) {
    let mut seen: HashSet<&ExtensionParam> = vec.iter().collect();
    for param in params {
        if seen.insert(&param) {
            vec.push(param);
        }
    }
}
```

**actix-web-0002:** Build `HashSet<&str>` from supported protocols before the loop:

```rust
// Before
if supported.contains(proto) { ... }  // O(P) Vec scan

// After
// CWE-407 fix: HashSet for O(1) contains() instead of O(P) Vec::contains scan.
let supported_set: HashSet<&&str> = supported.iter().collect();
if supported_set.contains(proto) { ... }
```

## Patch

`defects/actix-web/patch/actix-web-0001-ws-update-unique-hashset.patch`
`defects/actix-web/patch/actix-web-0002-ws-protocol-negotiate-hashset.patch`

## What We Ask

1. Confirm receipt and assign a GitHub Security Advisory or issue reference.
2. Validate the patch against your WebSocket and extension negotiation test suite.
3. Assess CVE eligibility — 300× overhead on every WebSocket upgrade response.
4. Coordinate a disclosure date — we are targeting 90 days from first contact.

Contact: see cover email. This brief is confidential until coordinated disclosure.
