Denial of Service (server crash due to unhandled TLSSocket error during TLS handshake)
Description
The commit adds a default error handler for TLSSocket instances during TLS connection initialization (tlsConnectionListener). Prior to this fix, if a TLS socket emitted an error before the user attached an error handler, it could trigger an unhandled 'error' event, potentially crashing the Node.js process (DoS via crash). The new code attaches a listener for 'error' on the socket (socket.on('error', onSocketTLSError)) to ensure the error is handled even if the application does not attach its own error handler. This resolves a class of denial-of-service scenarios where a misbehaving or abruptly destroyed TLS connection during initialization could crash the server. The patch is tied to CVE-2025-59465 and represents a genuine vulnerability fix rather than a mere dependency bump or test addition.
Proof of Concept
Proof-of-concept to demonstrate the vulnerability before the fix (server could crash when a TLSSocket emits an error with no user-attached error handler):
1) Run a minimal secure HTTP/2 server (pre-fix behavior) and do not attach an error handler to the TLS socket in the 'secureConnection' callback:
JavaScript (server.js, pre-fix scenario):
const fs = require('fs');
const http2 = require('http2');
const server = http2.createSecureServer({
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
});
server.on('secureConnection', (socket) => {
// Do NOT attach an error handler to the socket here
// This is the vulnerable scenario
// any error on this socket could crash the process if unhandled
});
server.listen(8443, () => console.log('secure server listening on 8443'));
2) Malicious client that triggers a TLS handshake error to produce an unhandled error on the server side:
Python client (attempts TLS handshake and then aborts to provoke a server TLS error):
import socket, ssl
import sys
host = '127.0.0.1'
port = 8443
s = socket.create_connection((host, port))
# Do not verify certificate; do not complete handshake gracefully
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
try:
with ctx.wrap_socket(s, server_hostname=host, do_handshake_on_connect=False) as ssock:
# Intentionally do not complete handshake
ssock.do_handshake()
except Exception as e:
print('Client handshake failed (expected):', e)
s.close()
sys.exit(0)
# If the server is vulnerable, this abrupt/failed handshake could emit an error on the
# TLSSocket without a user error handler and crash the server.
3) Expected behavior (post-fix):
- The server should not crash. The code path now installs a default 'error' listener on TLSSocket,
so an error during TLS initialization is handled gracefully by onSocketTLSError, avoiding process exit.
Note: In a real test, you would run the server with and without the patch (pre/post fix) and demonstrate that
an abrupt handshake error caused a crash in older versions but is suppressed in versions containing this fix.
Commit Details
Author: RafaelGSS
Date: 2025-10-31 19:27 UTC
Message:
lib: add TLSSocket default error handler
This prevents the server from crashing due to an unhandled rejection
when a TLSSocket connection is abruptly destroyed during initialization
and the user has not attached an error handler to the socket.
e.g:
```js
const server = http2.createSecureServer({ ... })
server.on('secureConnection', socket => {
socket.on('error', err => {
console.log(err)
})
})
```
PR-URL: https://github.com/nodejs-private/node-private/pull/750
Fixes: https://github.com/nodejs/node/issues/44751
Refs: https://hackerone.com/bugs?subject=nodejs&report_id=3262404
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
CVE-ID: CVE-2025-59465
Triage Assessment
Vulnerability Type: Denial of Service
Confidence: HIGH
Reasoning:
The commit adds a default error handler for TLSSocket to avoid unhandled errors that could crash the server during TLS connection setup when an error handler is not attached. This hardens error handling around TLS sockets and is tied to a CVE, indicating a vulnerability-related fix (denial of service via crash/unhandled error).
Verification Assessment
Vulnerability Type: Denial of Service (server crash due to unhandled TLSSocket error during TLS handshake)
Confidence: HIGH
Affected Versions: < 25.9.0
Code Diff
diff --git a/lib/internal/tls/wrap.js b/lib/internal/tls/wrap.js
index 82cf6832c3efa8..1cdfbf0f43fbd3 100644
--- a/lib/internal/tls/wrap.js
+++ b/lib/internal/tls/wrap.js
@@ -1252,6 +1252,7 @@ function tlsConnectionListener(rawSocket) {
socket[kErrorEmitted] = false;
socket.on('close', onSocketClose);
socket.on('_tlsError', onSocketTLSError);
+ socket.on('error', onSocketTLSError);
}
// AUTHENTICATION MODES