Apr 22, 2026·6 min read·17 visits
Unauthenticated attackers can send crafted WebSocket messages containing nested regex quantifiers to Signal K Server, triggering a ReDoS condition that blocks the Node.js event loop and causes 100% CPU exhaustion.
Signal K Server prior to version 2.25.0 contains a Regular Expression Denial of Service (ReDoS) vulnerability in its WebSocket subscription handling module. The application dynamically compiles unvalidated user input into regular expressions, allowing unauthenticated remote attackers to trigger catastrophic backtracking in the Node.js V8 engine. This results in complete resource exhaustion and immediate denial of service.
Signal K Server operates as a central data hub for marine vessels, heavily utilizing WebSockets for real-time telemetry streaming. The application processes client subscription requests to specific data paths using the SubscriptionManager component. Clients define their areas of interest using a context parameter, which the server translates into an internal filtering mechanism.
CVE-2026-39320 represents a Regular Expression Denial of Service (ReDoS) vulnerability in this subscription filtering logic. The application dynamically constructs regular expressions from unauthenticated, user-supplied context and path parameters. A failure to safely escape regex metacharacters allows attackers to inject malicious execution patterns.
Because Signal K Server runs on the Node.js runtime, it relies on a single-threaded event loop for JavaScript execution. When the V8 JavaScript engine evaluates an injected, highly complex regular expression against standard system identifiers, it enters a state of catastrophic backtracking. This synchronous computational operation halts all concurrent processing, resulting in an immediate and sustained denial of service.
The root cause lies in src/subscriptionmanager.ts, specifically within the contextMatcher and pathMatcher functions. These functions are responsible for converting wildcard-based string queries into native RegExp objects. The intended design allows simple wildcard filtering, translating paths like vessels.* into a matching regex pattern.
To achieve this behavior, the legacy implementation applied a naive string replacement strategy. It converted period characters to literal periods and asterisks to .* catch-all matchers. The implementation completely omitted sanitization for all other regular expression control characters, including grouping parentheses, alternation pipes, and repetition quantifiers.
This logic omission permits an attacker to supply a context string containing nested quantifiers. When the server concatenates this unsanitized input into the RegExp constructor, it creates a compiled pattern capable of exponential backtracking. The engine attempts to match the payload against long internal strings, typically the server's own 36-character UUID.
As the V8 regex engine evaluates the string, the nested groups cause it to compute every possible combination of character matches before ultimately failing. The computational time required scales exponentially with the length of the input string. This synchronous evaluation process blocks the Node.js event loop entirely.
The vulnerable implementation relied on manual, incomplete string replacement logic. By examining the source code prior to version 2.25.0, the failure to escape standard metacharacters is evident. The replacement sequence only accounted for two specific characters, leaving the rest of the regex syntax fully accessible to the end user.
// Vulnerable implementation in src/subscriptionmanager.ts
function contextMatcher(context: string) {
const pattern = context
.replace(/\./g, '\\.')
.replace(/\*/g, '.*');
return new RegExp(`^${pattern}$`);
}The patch introduced in commit 215d81eb700d5419c3396a0fbf23f2e246dfac2d addresses the flaw by integrating an external, robust regex escaping library. Rather than attempting to maintain a blocklist of dangerous characters, the fix employs an allowlist-like approach. It neutralizes the entire input string before selectively restoring the intended wildcard functionality.
// Patched implementation
import escapeStringRegexp from 'escape-string-regexp';
function contextMatcher(context: string) {
// Properly escape all metacharacters first
let pattern = escapeStringRegexp(context);
// Safely restore the intended wildcard behavior
pattern = pattern.replace(/\\\*/g, '.*');
return new RegExp(`^${pattern}$`);
}This architectural change ensures that any user-supplied parentheses, brackets, or plus signs are treated strictly as string literals by the regex engine. Consequently, the attacker loses the ability to define capturing groups or dynamic quantifiers, completely mitigating the catastrophic backtracking vector.
Exploitation requires no prior authentication and minimal network interaction. An attacker only needs TCP access to the target Signal K Server's WebSocket endpoint, typically exposed on port 3000. The attack initiates via a standard WebSocket upgrade request, followed by the transmission of a single crafted JSON payload.
The payload specifically targets the context field of a subscription request. The attacker structures the context to include a nested repetition pattern, followed by a character guaranteed not to exist at the end of the server's internal evaluation string. This suffix forces the worst-case time complexity path within the regex engine.
{
"context": "vessels.([a-z0-9:-]+)+!",
"subscribe": [
{
"path": "navigation.position",
"period": 1000
}
]
}Upon receiving this frame, the server maps the string ([a-z0-9:-]+)+! into a RegExp object. It then attempts to validate an incoming vessel identifier against it. When matching a standard vessel URN (e.g., urn:mrn:signalk:uuid:c0d79334-4e25-4245-8892-54e8ccc8021d), the engine matches the alphanumeric characters but fails at the literal exclamation mark boundary. The engine continuously backtracks through the overlapping plus quantifiers, locking the thread.
The successful execution of this attack results in a total denial of service for the target application. The underlying Node.js runtime operates concurrently using an asynchronous event loop, but native regex evaluations execute synchronously on the main thread. The catastrophic backtracking consumes 100% of the CPU core allocated to the Signal K process.
While the thread remains locked in the regex evaluation sequence, the server cannot process any pending or incoming network I/O. All subsequent REST API requests, WebSocket messages, and internal timers queue indefinitely. Existing client connections eventually drop as application-layer keep-alive mechanisms fail, rendering the system entirely unresponsive.
The CVSS v3.1 base score of 7.5 reflects the severity of this availability impact. The exploit execution requires low attack complexity, demands no privileges, and functions without any user interaction. System confidentiality and data integrity remain unaffected, as the vulnerability exclusively exhausts computational resources.
The recovery process requires manual administrative intervention or automated orchestration restarts. The affected process will not recover gracefully, as the regex evaluation time for a 36-character string with nested quantifiers can exceed multiple years of compute time. Administrators must forcefully terminate the process (SIGKILL) and allow a supervisor daemon to restart it.
The primary remediation strategy requires upgrading the Signal K Server software to version 2.25.0 or later. This release contains the complete cryptographic neutralization of user input prior to regex compilation, alongside new rate-limiting structures. Administrators must verify their package versions using npm or their container orchestrator management interfaces.
In environments where an immediate software upgrade is impossible, administrators can deploy Web Application Firewall (WAF) rules or reverse proxy filters to inspect WebSocket traffic. WAF signatures should be configured to aggressively drop any WebSocket frames containing repetitive regex metacharacters, specifically targeting patterns containing ( followed by + in the context JSON field.
Network-level restrictions provide an additional, effective layer of defense. By isolating the WebSocket endpoint behind a strict reverse proxy configuration or VPN gateway, administrators can restrict access to known, trusted client IP addresses. Implementing pre-connection authentication at the load balancer level completely removes the unauthenticated remote attack vector.
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.25.0 | 2.25.0 |
| Attribute | Detail |
|---|---|
| CVSS v3.1 | 7.5 (High) |
| CWE IDs | CWE-1333, CWE-400 |
| Attack Vector | Network (Unauthenticated) |
| Impact | Denial of Service (100% CPU exhaustion) |
| EPSS Score | 0.00041 (12.57th percentile) |
| Exploit Status | Proof of Concept (PoC) available |
| CISA KEV | Not Listed |
Inefficient Regular Expression Complexity
A CSV Formula Injection vulnerability (CWE-1236) exists in the Spree headless eCommerce platform within the customer export functionality. An unauthenticated attacker can register a customer profile containing malicious formula sequences in fields like the first name or last name. When an administrator exports the customer data to a CSV file and opens it in a spreadsheet application, the spreadsheet engine can interpret and execute these formulas, potentially leading to remote command execution on the administrator's workstation or out-of-band data exfiltration.
A Stored Cross-Site Scripting (XSS) vulnerability exists in WWBN AVideo versions up to and including 29.0. Unsanitized category descriptions are stored in the database and subsequently rendered as raw HTML in the Gallery view plugin, allowing low-privileged authenticated users to execute arbitrary JavaScript in the browsers of visiting users.
A critical supply chain compromise was identified in the Node.js package @cap-js/openapi at version 1.4.1. An attacker gained unauthorized publishing access to the npm registry and distributed a backdoored release that harvests sensitive developer credentials, environment variables, and SSH keys. The malicious code then exfiltrates the collected data to external actor-controlled servers.
An authenticated wallet credit bypass vulnerability exists in WWBN AVideo version 29.0 and earlier. The AuthorizeNet plugin includes an unfinished mockup endpoint, processPayment.json.php, which lacks actual transaction verification and hardcodes success. This allows any authenticated user to credit their wallet with arbitrary balances without making any payments.
An unauthenticated stored DOM-based Cross-Site Scripting (DOM XSS) vulnerability in the YPTSocket plugin of WWBN AVideo (formerly YouPHPTube) allows remote attackers to execute arbitrary JavaScript within the session context of administrative users. Unsanitized metadata parameters supplied during the WebSocket handshake are persisted in an SQLite database and broadcast to connected users. The frontend application processes these parameters through an unsafe jQuery append sink, leading to silent, high-impact administrative context compromise.
A path parsing and normalization inconsistency vulnerability exists in the Hono web framework prior to version 4.12.21. When hosting sub-applications via the app.mount() routing interface, Hono calculates the routing path prefix length on a percent-decoded representation of the URI but executes the path-slicing offset on the raw, percent-encoded string. This discrepancy results in malformed request paths being dispatched to mounted sub-applications, potentially leading to route bypasses, route confusion, and application-level Denial of Service.