# Per-user connection limits enforced to prevent slot exhaustion

- **Pattern:** `ab-000736` (`community-realtime.connection-management.per-user-connection-limits`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000736
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000736)

## Why it matters

Without a per-user connection ceiling, a single authenticated user — or a compromised account — can open thousands of simultaneous WebSocket connections. Each consumes a file descriptor, memory, and CPU for keepalive processing. At scale this constitutes a low-cost denial-of-service attack that degrades or crashes the server for every other user. CWE-770 (Allocation of Resources Without Limits) captures exactly this failure mode, and ISO 25010 performance-efficiency requires that resource consumption be bounded under adversarial load.

## Severity rationale

High because an unbounded connection count per user can exhaust server file descriptors and memory, causing service degradation for all users.

## Remediation

Track open connections per user in a server-side Map and reject the handshake once the limit is reached. Cap at 3–5 for most community apps.

```ts
const userConnections = new Map<string, Set<string>>();
const MAX_CONNECTIONS_PER_USER = 3;

io.use((socket, next) => {
  const userId = socket.userId;
  const conns = userConnections.get(userId) ?? new Set();
  if (conns.size >= MAX_CONNECTIONS_PER_USER) {
    return next(new Error('Connection limit reached'));
  }
  conns.add(socket.id);
  userConnections.set(userId, conns);
  socket.on('disconnect', () => conns.delete(socket.id));
  next();
});
```

The limit must be enforced in the middleware, not just configuration — a configured but unread value is not enforced.

## Detection

- **ID:** `per-user-connection-limits`
- **Severity:** `high`
- **What to look for:** Count all connection tracking mechanisms: connection counters, maps, middleware that rejects new connections. Enumerate per-user limit enforcement points. Check for a maximum threshold (typically no more than 10 connections per user).
- **Pass criteria:** The connection handler enforces a per-user maximum of at least 1 and no more than 10 connections. Exceeding the limit results in rejection or closure of excess connections. Report even on pass: "Per-user limit set to N connections."
- **Fail criteria:** No per-user connection limit is implemented, or the limit is unenforced in code.
- **Do NOT pass when:** A connection limit exists in configuration but the enforcement code never reads it — configured but unenforced limits are NOT a pass.
- **Skip (N/A) when:** Never — connection limits are critical for stability.
- **Cross-reference:** For rate limiting patterns and abuse prevention, the API Security Audit covers connection-level controls.
- **Detail on fail:** `"No per-user connection limit detected. A single user could theoretically open unlimited connections."`
- **Remediation:** Without per-user limits, a malicious or buggy client could exhaust server connection slots. Implement a limit:

  ```ts
  const userConnections = new Map<string, Set<string>>();
  const MAX_CONNECTIONS_PER_USER = 3;

  io.use((socket, next) => {
    const userId = socket.userId;
    if (!userConnections.has(userId)) {
      userConnections.set(userId, new Set());
    }
    const connections = userConnections.get(userId)!;
    if (connections.size >= MAX_CONNECTIONS_PER_USER) {
      return next(new Error('Too many connections'));
    }
    connections.add(socket.id);
    socket.on('disconnect', () => {
      connections.delete(socket.id);
    });
    next();
  });
  ```

## External references

- cwe CWE-770
- iso-25010 performance-efficiency.resource-utilization

Taxons: cost-efficiency

HTML version: https://auditbuffet.com/patterns/ab-000736
