Skip to content

WebSocket Login Endpoint Lacks Rate Limiting (Credential Brute-Force)

High
tkurki published GHSA-vmfm-ch9h-5c7g Apr 23, 2026

Package

npm signalk-server (npm)

Affected versions

<=2.24.0

Patched versions

2.25.0

Description

Summary

The HTTP login endpoints (POST /login and POST /signalk/v1/auth/login) are protected by express-rate-limit (default: 100 attempts per 10-minute window, configurable via HTTP_RATE_LIMITS). The WebSocket login path — sending {login: {username, password}} messages over an established WebSocket connection — calls app.securityStrategy.login() directly without any rate limiting.

An attacker can bypass HTTP rate limiting entirely by opening a WebSocket connection and attempting unlimited password guesses at the speed bcrypt allows (~20 attempts/sec with 10 salt rounds).

Details

Vulnerable code: src/interfaces/ws.ts, function processLoginRequest (lines 753-780)

The function directly calls app.securityStrategy.login(msg.login.username, msg.login.password) with no throttling or attempt tracking.

Rate-limited HTTP path for comparison: src/tokensecurity.ts lines 609-617 apply loginLimiter middleware to the HTTP login routes at line 637.

Steps to Reproduce

  1. Start Signal K server with security enabled
  2. Open a WebSocket connection to ws://server:3000/signalk/v1/stream?subscribe=none
  3. Wait for the hello message
  4. Send login attempts in rapid succession:
    {"requestId": "1", "login": {"username": "admin", "password": "guess1"}}
    {"requestId": "2", "login": {"username": "admin", "password": "guess2"}}
  5. Observe that all attempts are processed without any 429 response or throttling
  6. For comparison, send 100+ HTTP POST requests to /signalk/v1/auth/login — the 101st returns 429

A POC script is available that demonstrates both the HTTP rate limiting working correctly and the WebSocket path accepting unlimited attempts.

Impact

  • Credential brute-forcing via the WebSocket protocol at ~20 attempts/sec (bcrypt-limited)
  • Complete bypass of the HTTP rate limiting defense
  • A single WebSocket connection is sufficient for unlimited attempts
  • With multiple parallel connections, throughput multiplies
  • A 10,000-word dictionary attack completes in ~8 minutes over a single connection

Signal K servers are commonly deployed on boat networks where they may be accessible to other devices on the same LAN.

CWE

CWE-307: Improper Restriction of Excessive Authentication Attempts

Suggested Fix

Track failed login attempts per remote IP in a shared store (or reuse the existing express-rate-limit store) that is checked in both the HTTP login middleware and the processLoginRequest WebSocket handler.

Context

Found while building an open source maritime security scanner. Happy to submit a PR with a fix if helpful. Verified on v2.24.0 (current master).

— Mark Curphey

Severity

High

CVE ID

CVE-2026-41893

Weaknesses

No CWEs