{"id":"CVE-2026-41893","aliases":["EUVD-2026-28922","GHSA-vmfm-ch9h-5c7g"],"status":"published","title":"Signal K Server's WebSocket Login Endpoint Lacks Rate Limiting (Credential Brute-Force)","description":"Signal K Server is a server application that runs on a central hub in a boat. Prior to version 2.25.0, 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). This issue has been patched in version 2.25.0.","severity":{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00327,"percentile":0.25956,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-307"],"published":"2026-05-04T20:52:06Z","modified":"2026-10-28T02:30:22Z","fixes":[{"ecosystem":"npm","package":"signalk-server","fixed_in":["2.25.0"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"signalk-server","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.24.0"},{"fixed":"2.25.0"}]}]},{"source":"osv","ecosystem":"npm","package":"signalk-server","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.25.0"}]}]}],"products":[{"vendor":"signalk","product":"signal_k_server"},{"vendor":"signalk","product":"signalk-server"}],"references":[{"url":"https://github.com/SignalK/signalk-server/security/advisories/GHSA-vmfm-ch9h-5c7g","tags":["x_refsource_CONFIRM","exploit","Exploit","Mitigation","Vendor Advisory","advisory","web"]},{"url":"https://github.com/SignalK/signalk-server/pull/2568","tags":["x_refsource_MISC","Issue Tracking","Patch","fix","web"]},{"url":"https://github.com/SignalK/signalk-server/commit/215d81eb700d5419c3396a0fbf23f2e246dfac2d","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://github.com/SignalK/signalk-server/releases/tag/v2.25.0","tags":["x_refsource_MISC","Product","Release Notes","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-41893","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-vmfm-ch9h-5c7g"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/41xxx/CVE-2026-41893.json","tags":["advisory"]},{"url":"https://github.com/SignalK/signalk-server","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-41893","title":"Signal K Server's WebSocket Login Endpoint Lacks Rate Limiting (Credential Brute-Force)","description":"Signal K Server is a server application that runs on a central hub in a boat. Prior to version 2.25.0, 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). This issue has been patched in version 2.25.0.","status":"published","published":"2026-05-09T19:12:10.082Z","modified":"2026-05-14T17:50:55.289Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high","assessor":"cna"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T13:41:08.498858Z"}],"euvd":[{"id":"EUVD-2026-28922","description":"Signal K Server is a server application that runs on a central hub in a boat. Prior to version 2.25.0, 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). This issue has been patched in version 2.25.0.","status":"published","published":"2026-05-09T19:12:10Z","modified":"2026-05-14T17:50:55Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high"}],"updated_at":"2026-11-02T19:04:31.113278Z"}],"ghsa":[{"id":"GHSA-vmfm-ch9h-5c7g","title":"Signal K Server's WebSocket Login Endpoint Lacks Rate Limiting (Credential Brute-Force)","description":"## Summary\n\nThe 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.\n\nAn 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).\n\n## Details\n\n**Vulnerable code:** `src/interfaces/ws.ts`, function `processLoginRequest` (lines 753-780)\n\nThe function directly calls `app.securityStrategy.login(msg.login.username, msg.login.password)` with no throttling or attempt tracking.\n\n**Rate-limited HTTP path for comparison:** `src/tokensecurity.ts` lines 609-617 apply `loginLimiter` middleware to the HTTP login routes at line 637.\n\n## Steps to Reproduce\n\n1. Start Signal K server with security enabled\n2. Open a WebSocket connection to `ws://server:3000/signalk/v1/stream?subscribe=none`\n3. Wait for the hello message\n4. Send login attempts in rapid succession:\n   ```json\n   {\"requestId\": \"1\", \"login\": {\"username\": \"admin\", \"password\": \"guess1\"}}\n   {\"requestId\": \"2\", \"login\": {\"username\": \"admin\", \"password\": \"guess2\"}}\n   ```\n5. Observe that all attempts are processed without any 429 response or throttling\n6. For comparison, send 100+ HTTP POST requests to `/signalk/v1/auth/login` — the 101st returns 429\n\nA POC script is available that demonstrates both the HTTP rate limiting working correctly and the WebSocket path accepting unlimited attempts.\n\n## Impact\n\n- Credential brute-forcing via the WebSocket protocol at ~20 attempts/sec (bcrypt-limited)\n- Complete bypass of the HTTP rate limiting defense\n- A single WebSocket connection is sufficient for unlimited attempts\n- With multiple parallel connections, throughput multiplies\n- A 10,000-word dictionary attack completes in ~8 minutes over a single connection\n\nSignal K servers are commonly deployed on boat networks where they may be accessible to other devices on the same LAN.\n\n## CWE\n\nCWE-307: Improper Restriction of Excessive Authentication Attempts\n\n## Suggested Fix\n\nTrack 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.\n\n## Context\n\nFound while building an open source maritime security scanner. Verified on v2.24.0 (current master).\n\nDiscovered by Mark Curphey","status":"published","published":"2026-05-04T20:52:06Z","modified":"2026-05-13T13:41:35Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T14:40:07.01746Z"}],"nvd":[{"id":"CVE-2026-41893","description":"Signal K Server is a server application that runs on a central hub in a boat. Prior to version 2.25.0, 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). This issue has been patched in version 2.25.0.","status":"published","published":"2026-05-09T20:16:27.273Z","modified":"2026-07-24T19:10:00.16Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"high","assessor":"secondary"},{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N","level":"high","assessor":"primary"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T14:12:18.239974Z"}],"osv":[{"id":"CVE-2026-41893","title":"Signal K Server's WebSocket Login Endpoint Lacks Rate Limiting (Credential Brute-Force)","description":"Signal K Server is a server application that runs on a central hub in a boat. Prior to version 2.25.0, 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). This issue has been patched in version 2.25.0.","status":"published","published":"2026-05-09T19:12:10.082Z","modified":"2026-10-28T02:30:22.606810968Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T15:45:03.764807Z"},{"id":"GHSA-vmfm-ch9h-5c7g","title":"Signal K Server's WebSocket Login Endpoint Lacks Rate Limiting (Credential Brute-Force)","description":"## Summary\n\nThe 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.\n\nAn 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).\n\n## Details\n\n**Vulnerable code:** `src/interfaces/ws.ts`, function `processLoginRequest` (lines 753-780)\n\nThe function directly calls `app.securityStrategy.login(msg.login.username, msg.login.password)` with no throttling or attempt tracking.\n\n**Rate-limited HTTP path for comparison:** `src/tokensecurity.ts` lines 609-617 apply `loginLimiter` middleware to the HTTP login routes at line 637.\n\n## Steps to Reproduce\n\n1. Start Signal K server with security enabled\n2. Open a WebSocket connection to `ws://server:3000/signalk/v1/stream?subscribe=none`\n3. Wait for the hello message\n4. Send login attempts in rapid succession:\n   ```json\n   {\"requestId\": \"1\", \"login\": {\"username\": \"admin\", \"password\": \"guess1\"}}\n   {\"requestId\": \"2\", \"login\": {\"username\": \"admin\", \"password\": \"guess2\"}}\n   ```\n5. Observe that all attempts are processed without any 429 response or throttling\n6. For comparison, send 100+ HTTP POST requests to `/signalk/v1/auth/login` — the 101st returns 429\n\nA POC script is available that demonstrates both the HTTP rate limiting working correctly and the WebSocket path accepting unlimited attempts.\n\n## Impact\n\n- Credential brute-forcing via the WebSocket protocol at ~20 attempts/sec (bcrypt-limited)\n- Complete bypass of the HTTP rate limiting defense\n- A single WebSocket connection is sufficient for unlimited attempts\n- With multiple parallel connections, throughput multiplies\n- A 10,000-word dictionary attack completes in ~8 minutes over a single connection\n\nSignal K servers are commonly deployed on boat networks where they may be accessible to other devices on the same LAN.\n\n## CWE\n\nCWE-307: Improper Restriction of Excessive Authentication Attempts\n\n## Suggested Fix\n\nTrack 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.\n\n## Context\n\nFound while building an open source maritime security scanner. Verified on v2.24.0 (current master).\n\nDiscovered by Mark Curphey","status":"published","published":"2026-05-04T20:52:06Z","modified":"2026-05-13T13:47:18.329474Z","cvss":[{"version":"4.0","score":8.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N","level":"high"}],"cwes":["CWE-307"],"updated_at":"2026-11-02T15:46:57.348035Z"}]}}
