Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessClient connects to clock-skewed OPC UA server
-
DeliveryKeepalive read returns BadInvalidTimestamp
-
ExploitManager misreads it as network outage
-
ExecutionForces transport reconnection each cycle
-
PersistFailed HEL/ACK leaks FIN-WAIT-2 socket
-
ImpactFD/memory exhaustion crashes process (OOM)
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A06:2025 - Insecure Design
ASVS 5.0
V2 - Validation and Business Logic Resource consumption limits
MITRE ATT&CK
1 technique across 1 tactic: Impact The technique list with ATT&CK links and the kill-chain view is part of the Basic plan and up. |
| Exploitation Conditions | Requires the node-opcua client to connect to an OPC UA server whose clock is skewed beyond the server's RequestHeader timestamp-tolerance window (reporter observed ~50 minutes), causing repeated BadInvalidTimestamp responses; the default keepSessionAlive: true configuration is needed so the keepalive manager pings and misclassifies the status code as a network outage. Sustained leakage further depends on the peer (typically a PLC) not completing the TCP close, leaving sockets stuck in FIN-WAIT-2. Limiting factors: this is environmental/operational rather than a crafted-payload attack (AC:H), impact is confined to the client process/container, and it does not affect clients connected to time-synchronized servers or those that disable keepalive; no authentication is involved because the tested setup uses securityMode/securityPolicy None. |
| Impact | This is a genuine but conditional availability issue, not a broad-impact priority. The vendor CVSS of 7.0 (AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H, CWE-400) correctly captures the DoS core (A:H) and the high complexity (AC:H) driven by the required clock-skew precondition, but the C:L and I:L are not supported by the technical description - the socket leak and OOM kill produce no disclosure or modification of data, so confidentiality and integrity impact should be N, not L. This overstates the base score slightly. The 'attacker' is not a classic remote adversary sending malicious payloads: the crash is triggered by a client connecting to an OPC UA server whose clock is skewed beyond the server's timestamp-tolerance window, so the harmful condition originates from the connected server/environment rather than a targeted exploit. No EPSS score, no CISA KEV listing, and no public weaponized exploit were provided, so there is no evidence of active exploitation; the detailed reporter reproduction demonstrates reliability but is not an exploit binary. Net: a real reliability/resource-exhaustion defect worth patching for industrial OPC UA client operators, but real-world risk is bounded by the specific clock-skew and non-default operational conditions rather than being a mass-exploitable network vulnerability. |
| Exploit ScenarioDerived | A node-opcua client (default keepSessionAlive: true) connects to an industrial PLC OPC UA server whose clock is ~50 minutes ahead, exceeding the server's timestamp tolerance. Each keepalive cycle (every 3s) receives BadInvalidTimestamp, which the keepalive manager misclassifies as a network outage and forces a full transport reconnection; each failed HEL/ACK handshake calls socket.end() and leaks a socket in FIN-WAIT-2 (~20/min, ~1200/hr), exhausting file descriptors/memory until the container is OOM-killed. No public exploit code exists; the reporter supplied a step-by-step reproduction rather than a weaponized tool. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Sep 16, 2026
Socket and memory exhaustion in node-opcua clients (packages node-opcua, node-opcua-client and node-opcua-transport, versions 2.0.0 through 2.169.x) can terminate the Node.js process or container via OOM kill when the client is configured with the default keepSessionAlive: true and connects to an OPC UA server whose clock is skewed well beyond the server's RequestHeader timestamp tolerance. Two compounding defects cause this: the keepalive manager misclassifies the server's BadInvalidTimestamp status code as a network outage and forces a full transport reconnection on every keepalive cycle, while the HEL/ACK failure handler calls socket.end() instead of socket.destroy(), leaving each abandoned connection in FIN-WAIT-2 so leaked sockets accumulate roughly once per keepAliveInterval (about 1,200 per hour at the default 3-second interval). The vector is network-reachable and unauthenticated (PR:N), but exploitation is high-complexity and conditional on clock skew plus a peer that never completes the TCP close; no public exploit code or confirmed active exploitation was identified at time of analysis, and impact is confined to availability of the affected client process (C:N/I:N/A:H).
RemediationAI
Vendor-released patch: upgrade node-opcua, node-opcua-client and node-opcua-transport to 2.170.0 or later, which resolves both defects - the transport handler now destroys rather than half-closes the socket on HEL/ACK failure, and the keepalive manager checks the ServiceFault status and only forces reconnection on genuine session-invalidating codes (BadSessionIdInvalid, BadSessionClosed) while treating other service results as keepalive failures and applying exponential backoff capped at 60 seconds (see PR https://github.com/node-opcua/node-opcua/pull/1497, commits 1959cbb8946b386d2e24a1cce05b7148099d36e7 and 481664fa6ba8204737c5a92797ff68c3ae780c1c, advisory https://github.com/node-opcua/node-opcua/security/advisories/GHSA-r2pf-9cw4-5j65). If immediate upgrade is not possible, set keepSessionAlive: false on the client to eliminate the reconnection loop that drives the leak - the trade-off is loss of automatic session-liveness detection, so stale sessions must be handled by application-level retry logic; alternatively, synchronize client and server clocks (NTP/PTP) so timestamps fall inside the server's tolerance window and BadInvalidTimestamp is never returned, which is the most faithful mitigation for PLC environments but depends on change control over the field device. Reducing keepAliveInterval only slows the leak rate and should not be relied on. As a containment measure, cap the client process/container with a memory limit and file-descriptor ulimit plus monitoring on FIN-WAIT-2 socket counts (ss -antp | grep FIN-WAIT-2) so restarts occur before OOM kill affects dependent workloads.
Affected VersionsENISA
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 3 packages in npm
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
node-opcua is a Node.js/TypeScript implementation of the OPC UA industrial protocol stack, published as a set of interdependent npm packages (node-opcua, node-opcua-client, node-opcua-transport). The defect spans two layers of that stack. At the transport layer, ClientTCP_transport._on_ACK_response() handles failure of the HEL/ACK handshake that opens an OPC UA secure channel; instead of destroying the socket it calls socket.end(), which transmits a TCP FIN and then waits for the peer to close its own side. When the remote peer (typically an industrial PLC) never responds with its FIN, the connection lingers in FIN-WAIT-2, holding a file descriptor and associated kernel memory indefinitely. At the session layer, ClientSessionKeepAliveManager._ping_server() periodically reads Server.ServerStatus.CurrentTime; because the client's RequestHeader.timestamp falls outside the server's tolerance window when the server clock is skewed (the reporter observed ~50 minutes), the server returns the application-level status BadInvalidTimestamp. The manager treats any error as a fatal outage, emits 'failure' and calls terminateConnection()/forceConnectionBreak(), so every keepalive tick produces a fresh reconnect attempt and, via the transport bug, a fresh leaked socket. The root cause class is CWE-400 (Uncontrolled Resource Consumption), and the assessed impact is availability-only (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H) because the condition is environmental/operational rather than a crafted payload and the leakage is bounded to the client process or container.
Know when Node.js gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H
Harmful condition arrives from the connected server over the network (AV:N) but needs specific clock skew (AC:H); pure resource-exhaustion crash gives A:H with no confidentiality or integrity impact.
Primary rating from Vendor (https://github.com/node-opcua/node-opcua).
CVSS VectorVendor: https://github.com/node-opcua/node-opcua
DescriptionCVE.org
SUMMARY ------- A combination of bugs in node-opcua causes unlimited TCP socket accumulation (FIN-WAIT-2 state) during automatic reconnection, leading to memory exhaustion and eventual container/process crash (OOM kill). The issue is triggered by the default configuration (keepSessionAlive: true) when the OPC UA server has clock skew relative to the client.
Affected version: Tested on 2.169.0 (latest as of April 2026).
ENVIRONMENT -----------
- Node.js: v24.11.0
- node-opcua: 2.169.0
- OS: Linux (containerized via Podman, slirp4netns networking)
- OPC UA Server: Industrial PLC (opc.tcp endpoint), clock skew of ~50 minutes ahead of client
- Client config: keepSessionAlive: true (default), keepAliveInterval: 3000, securityMode: None, securityPolicy: None
ROOT CAUSE ANALYSIS -------------------
Bug #1 - ClientTCP_transport._on_ACK_response() uses socket.end() instead of socket.destroy()
File: node-opcua-transport/src/client_tcp_transport.ts, _on_ACK_response() method
When the HEL/ACK handshake fails during a reconnection attempt, the error handler calls socket.end():
if (err || !data) { externalCallback(err || new Error("no data")); if (this._socket) { this._socket.end(); // <- sends TCP FIN, leaves socket in FIN-WAIT-2 } }
socket.end() sends a TCP FIN and waits for the peer to close its side. If the peer doesn't respond (common with PLCs), the socket remains in FIN-WAIT-2 state indefinitely, leaking file descriptors and memory. During rapid reconnection cycles (triggered by Bug #2 below), every failed HEL/ACK creates a new leaked socket.
---
Bug #2 - ClientSessionKeepAliveManager._ping_server() treats BadInvalidTimestamp as network outage
File: node-opcua-client/src/client_session_keepalive_manager.ts, _ping_server() method
The keepalive manager reads Server.ServerStatus.CurrentTime on each ping cycle. If the server responds with BadInvalidTimestamp (because the client's RequestHeader.timestamp falls outside the server's tolerance window due to clock skew), the manager treats this as a fatal network error:
// Any error -> emit("failure") -> terminateConnection() -> forceConnectionBreak()
This triggers a full transport-level reconnection on every keepalive cycle (every keepAliveInterval ms). Combined with Bug #1, each reconnection attempt leaks one TCP socket in FIN-WAIT-2. Impact amplification: With keepAliveInterval: 3000 (3 seconds), the client leaks ~20 sockets/minute, ~1200/hour, exhausting resources in hours.
REPRODUCTION STEPS ------------------
- Set up an OPC UA server with a clock skewed more than the server's timestamp tolerance ahead of the client.
- Connect using node-opcua with default settings (keepSessionAlive: true).
- Monitor TCP sockets: ss -antp | grep FIN-WAIT-2 | wc -l
- Observe FIN-WAIT-2 count growing continuously (approximately one per keepalive interval).
- Eventually the process runs out of file descriptors or memory and crashes.
SUGGESTED FIXES ---------------
For Bug #1 (_on_ACK_response):
// Replace socket.end() with socket.destroy() if (this._socket) { this._socket.destroy(); }
For Bug #2 (_ping_server): Distinguish between transport-level errors (actual network outage) and application-level OPC UA status codes like BadInvalidTimestamp. The latter indicates the server is reachable and the session is alive - only the timestamp validation failed. The keepalive should not trigger reconnection.
REPORTER -------- Marco Velluso @Velluso [velluso.marco64@gmail.com](mailto:velluso.marco64@gmail.com) Requesting CVE assignment and credit as reporter upon fix publication.
Articles & Coverage 1
Technical POC Analysis
CWE-400 (Uncontrolled Resource Consumption), realized as two compounding defects in the node-opcua client stack.
Full technical POC analysis - root cause, step-by-step exploitation and patch breakdown - is part of the Pro and Business plans.
Latest POC
1 PoC candidate from github (unverified)
Sign in to open the public PoC links collected for this CVE.
Executive ViewAI
A resource-exhaustion flaw in the widely used node-opcua client libraries (versions 2.0.0 through 2.169.x) can crash Node.js processes and container instances through out-of-memory kills whenever a client with default keepalive settings connects to an OPC UA server whose clock is skewed. Organizations relying on these JavaScript clients for industrial telemetry, SCADA integration, or manufacturing data pipelines face availability loss, container restart loops, and possible cascading monitoring gaps rather than any data compromise. Because the vulnerable code ships in a common open-source dependency, the exposure footprint may extend beyond teams that are aware they use it.
Apply vendor patch.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
SSVC AssessmentENISA
Priority Score
Attack Technique
Denial of Service attacks render applications or systems unavailable by overwhelming resources or triggering failure conditions.
Remote code execution in n8n's workflow expression evaluation system allows an authenticated user with workflow creation
A vulnerability in the NuPoint Unified Messaging (NPM) component of Mitel MiCollab through 9.8 SP1 FP2 (9.8.1.201) could
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Denial of service against HTTP/2 server implementations allows remote unauthenticated attackers to exhaust server resour
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
EUVD-2026-80869
GHSA-r2pf-9cw4-5j65
NVD
CVE.org
EPSS
Vulnrichment
Exploit-DB