Skip to main content
← Back to list
01Issue
BugOpenSwamp CLI
AssigneesNone

Relationships

#1615 WebSocket auth rate limiter blocks legitimate users when sharing IP with a failing client

Opened by stack72 · 8/12/2026

Description

The WebSocket auth rate limiter is keyed by source IP address with a limit of 5 attempts per 60-second window. In Kubernetes environments, multiple clients can share the same internal IP (e.g. workers and CLI users connecting via a ClusterIP service or from the same node). A single client with a bad token retrying every second burns through the rate limit budget and blocks all other clients on the same IP from authenticating — including legitimate users with valid tokens.

Reproduction

  1. A remote worker (platform-fleet-gke-svc) connects to swamp serve with a token whose model definition doesn't exist
  2. The worker retries every ~1 second
  3. After 5 failures, the rate limiter blocks IP [IP-1] for 55 seconds
  4. A legitimate user doing swamp access grant list --server arrives from the same IP
  5. User gets HTTP 429 (rate-limited) before their token is even checked
  6. User sees "Authentication failed" with no indication they were rate-limited

Impact

  • Legitimate users are locked out of the server for up to 60 seconds at a time
  • The failing client's retry loop ensures the rate limit never clears — every 60 seconds a new window opens, the worker burns 5 attempts in 5 seconds, and the IP is blocked again for another 55 seconds
  • The user-facing error message ("Authentication failed — run: swamp auth server-login") is misleading — the issue is rate limiting, not an invalid credential
  • In practice, the user is permanently locked out as long as the failing client runs

Root Cause

Rate limiter at serve.ts:185-218:

  • Keyed by raw source IP (remoteAddr)
  • 5 attempts per 60-second window (MAX_AUTH_ATTEMPTS = 5, AUTH_WINDOW_MS = 60_000)
  • A failed auth counts against the IP's budget
  • A successful auth resets the counter (clearRateLimit), but a rate-limited connection is rejected before auth is attempted, so there's no path to clearing it while the bad client keeps retrying

Proposed Fix

Several options (not mutually exclusive):

  1. Key rate limiting by token name, not IP — failed auths for platform-fleet-gke-svc should not affect oauth-cb23718d. Rate limit the specific credential, not the network address.

  2. Separate the rate limit response from the auth error — return HTTP 429 with a Retry-After header instead of 401, so clients can distinguish "try again later" from "your token is bad" and avoid pointless re-login attempts.

  3. Exempt authenticated connections — only rate-limit the pre-auth phase. If the token is syntactically valid (passes splitServerToken), attempt validation regardless of rate limit state. Only rate-limit connections with no token or malformed tokens.

  4. Per-principal rate limiting — after extracting the token name from the <name>.<secret> format, rate-limit per token name rather than per IP. This isolates misbehaving clients without affecting others.

  5. Exponential backoff signal — return 429 with increasing Retry-After values to slow down retry loops from failing clients.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED

Open

8/12/2026, 12:36:16 AM

No activity in this phase yet.

03Sludge Pulse

Sign in to post a ripple.