High

node-opcua: TCP Socket Leak (FIN-WAIT-2) via keepalive reconnection cycle - Resource Exhaustion

  • Disclosed: 16.09.2026
  • Updated: 11.10.2026 10:22

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

  1. Set up an OPC UA server with a clock skewed more than the server's timestamp tolerance ahead of the client.
  2. Connect using node-opcua with default settings (keepSessionAlive: true).
  3. Monitor TCP sockets: ss -antp | grep FIN-WAIT-2 | wc -l
  4. Observe FIN-WAIT-2 count growing continuously (approximately one per keepalive interval).
  5. 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 Requesting CVE assignment and credit as reporter upon fix publication.

Affected software

Click a technology to see all vulnerabilities affecting it.

PlatformPackageVulnerable versionsFixed in
npm package node-opcua >= 2.0.0, < 2.170.0 2.170.0
npm package node-opcua-client >= 2.0.0, < 2.170.0 2.170.0
npm package node-opcua-transport >= 2.0.0, < 2.170.0 2.170.0

References

CVSS score 7/10
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:H
Weakness (CWE)
CWE-400
Platform
npm
Package
node-opcua, node-opcua-client, node-opcua-transport
Disclosed
16.09.2026
Updated
11.10.2026 10:22

Sources and licenses

OSV / GitHub Advisory Database - GHSA-r2pf-9cw4-5j65 - CC BY 4.0

Vulnerability history: node-opcua

All published vulnerabilities of this package (npm package), newest first. Shows whether this is a one-off slip or a package that needs watching.

Total entries
6
First → latest
08.2022 09.2026
Without a fix
1
Exploited in attacks
0

Severity breakdown

  • High 6

Disclosures per year

  1. 2022: 3
  2. 2023: 0
  3. 2024: 0
  4. 2025: 0
  5. 2026: 3
  1. node-opcua: TCP Socket Leak (FIN-WAIT-2) via keepalive reconnection cycle - Resource Exhaustion this entry
    High · 7.0 CVE-2026-68904 >= 2.0.0, < 2.170.0 2.170.0
  2. High · 7.5 CVE-2022-21208 < 2.74.0 2.74.0

Know which vulnerabilities affect your application

With the DockRay integration and software inventory enabled, DockRay checks reported component versions against known vulnerabilities and notifies you about confirmed matches. Coverage depends on the supported technology and available advisory data.

Connect your application
DockRay newsletter

Application security in your inbox

Important vulnerabilities, actionable guidance and practical advice for your applications. Choose your technologies and follow what matters to your project.

  • A daily digest of new vulnerabilities, critical ones included.
  • Notifications about important updates.
  • Practical advice on application security and monitoring.

Leave empty to receive updates for every technology.

Free to subscribe. Unsubscribe with one click in any email.