CVE-2026-68904 Overview
CVE-2026-68904 is a resource exhaustion vulnerability [CWE-400] in node-opcua, an OPC UA implementation for TypeScript and Node.js. Versions from 2.0.0 through 2.169.x are affected. When an OPC UA server experiences clock skew and returns BadInvalidTimestamp responses, node-opcua clients using the default keepSessionAlive setting misinterpret the server-originated ServiceFault as a network outage. The client then forces repeated transport reconnects, leaking sockets in FIN-WAIT-2 and accumulating file descriptors and memory. Sustained repetition at the keepalive interval exhausts client resources until the process or container terminates. The issue is fixed in version 2.170.0.
Critical Impact
Remote OPC UA servers with clock skew can trigger unbounded reconnect loops in node-opcua clients, causing file descriptor and memory exhaustion until the client process crashes.
Affected Products
- node-opcua versions 2.0.0 through 2.169.x
- Node.js and TypeScript applications using node-opcua client libraries
- Industrial control system (ICS) integrations relying on node-opcua for OPC UA communication
Discovery Timeline
- 2026-09-16 - CVE-2026-68904 published to the National Vulnerability Database
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-68904
Vulnerability Analysis
The vulnerability resides in two interacting components of the node-opcua client. The ClientSessionKeepAliveManager._ping_server routine issues periodic keepalive requests to detect session health. When the server returns a ServiceFault such as BadInvalidTimestamp caused by clock skew, the manager classifies the application-layer fault as a transport failure. This misclassification triggers an immediate transport reconnect through ClientTCP_transport. The reconnect cycle repeats every keepAliveInterval, producing a persistent loop that consumes client resources without any authentication requirement.
Root Cause
Two distinct defects combine to produce the exhaustion condition. First, _ping_server does not distinguish server-originated OPC UA ServiceFault responses from actual socket or protocol errors. Second, ClientTCP_transport._on_ACK_response calls socket.end() after a failed HEL/ACK negotiation instead of destroying the socket. When the peer does not send FIN, the local half-closed socket lingers in FIN-WAIT-2, holding a file descriptor and buffers. Repeated reconnect attempts accumulate these orphaned sockets, exhausting system resources.
Attack Vector
An attacker capable of influencing an OPC UA server's clock, or an operator of a malicious or misconfigured server, can trigger the loop simply by responding with BadInvalidTimestamp to keepalive requests. No credentials or user interaction are required. The vulnerability is exploitable over the network against any node-opcua client that connects to the affected server with default keepalive settings.
// Patch: release socket immediately on HEL/ACK failure
// Source: https://github.com/node-opcua/node-opcua/commit/1959cbb8946b386d2e24a1cce05b7148099d36e7
this._counter += 1;
if (err || !data) {
- externalCallback(err || new Error("no data"));
if (this._socket) {
- this._socket.end();
+ const s = this._socket;
+ this._socket = null;
+ s.destroy();
}
+ externalCallback(err || new Error("no data"));
} else {
this._handle_ACK_response(data, externalCallback);
}
// Patch: distinguish server-originated faults from transport errors
// Source: https://github.com/node-opcua/node-opcua/commit/4d59197e2dbd82791d7f36dad7da178715e0c27a
import type { StatusCode } from "node-opcua-status-code";
import { StatusCodes } from "node-opcua-status-code";
interface ServiceFaultAnnotatedError extends Error {
response?: {
responseHeader?: {
serviceResult?: StatusCode;
};
};
}
Detection Methods for CVE-2026-68904
Indicators of Compromise
- Repeated node-opcua client log entries showing keepalive failures paired with reconnect attempts at the configured keepAliveInterval.
- Growing count of TCP sockets in FIN-WAIT-2 state associated with the client process.
- Steadily increasing file descriptor and memory usage in Node.js processes running node-opcua clients.
- Server-side BadInvalidTimestamp responses correlated with client reconnect spikes.
Detection Strategies
- Inspect package.json and lockfiles across Node.js deployments for node-opcua versions earlier than 2.170.0.
- Monitor process-level file descriptor counts using lsof -p <pid> or /proc/<pid>/fd for node-opcua client processes.
- Enable node-opcua debug logging and watch for repeated keepalive_failure events emitted by ClientSessionKeepAliveManager.
Monitoring Recommendations
- Alert on Node.js process memory or file descriptor growth exceeding baseline in industrial workloads.
- Track TCP socket states with ss -tan state fin-wait-2 and alert when counts exceed a threshold per host.
- Correlate OPC UA server clock synchronization health with client reconnect metrics.
How to Mitigate CVE-2026-68904
Immediate Actions Required
- Upgrade all node-opcua client deployments to version 2.170.0 or later.
- Audit dependency trees for transitive uses of node-opcua and rebuild affected artifacts.
- Verify NTP synchronization on all OPC UA servers to reduce clock skew that triggers BadInvalidTimestamp responses.
- Restart long-running node-opcua client processes after patching to release leaked sockets.
Patch Information
The fix is delivered in node-opcua v2.170.0. It introduces exponential backoff for consecutive keepalive ServiceFaults, distinguishes server-originated faults from transport errors, and calls socket.destroy() on HEL/ACK failure. Details are documented in the GHSA-r2pf-9cw4-5j65 advisory and consolidated in Pull Request #1497.
Workarounds
- Disable the default keepSessionAlive behavior on client sessions where feasible until the upgrade is applied.
- Increase the keepAliveInterval to slow socket accumulation and buy time to detect the condition.
- Restrict client connections to trusted OPC UA servers with verified time synchronization.
- Apply process-level ulimit and container memory limits so that exhaustion triggers a controlled restart rather than host-wide impact.
# Upgrade node-opcua to the patched release
npm install node-opcua@^2.170.0
# Verify installed version
npm ls node-opcua
# Inspect FIN-WAIT-2 socket accumulation on Linux hosts
ss -tan state fin-wait-2 | wc -l
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.