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
Lifecycle Timeline
4DescriptionCVE.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
AnalysisAI
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). …
Unlock full vulnerability intelligence
- Risk assessment & exploitation conditions
- Attack chain visualization
- Remediation with exact patch versions
- Threat intelligence from 22 sources
- Personal watchlist & email alerts
Free forever · No credit card required
Attack ChainAIDerived
Hypothetical attack flow derived from CVE metadata
Vulnerability AssessmentAI
| Exploitation | 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. … Additional conditions and limiting factors are described in the full assessment. |
| Risk Assessment | This is a genuine but conditional availability issue, not a broad-impact priority. … Full risk analysis with EPSS, KEV, and SSVC signal comparison available after sign-in. |
| Exploit Scenario | Full exploit scenario with step-by-step reproduction available after sign-in. |
| Remediation | 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). … Detailed patch versions, workarounds, and compensating controls in full report. |
Recommended ActionAI
Within 24 hours, inventory every application, container image, and CI pipeline that depends on node-opcua, node-opcua-client, or node-opcua-transport in the 2.0.0 through 2.169.x range, and confirm which deployments run with the default keepSessionAlive: true; where immediate upgrades are not possible, set keepSessionAlive to false and enforce container memory limits plus restart backoff to contain OOM kills. …
Sign in for detailed remediation steps and compensating controls.
Threat intelligence, references, and detailed analysis are available after sign-in.
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
The AES-NI implementation in OpenSSL before 1.0.1t and 1.0.2 before 1.0.2h does not consider memory allocation during a
Same weakness CWE-400 – Uncontrolled Resource Consumption
View allSame technique Denial Of Service
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-80869
GHSA-r2pf-9cw4-5j65