-
-
Notifications
You must be signed in to change notification settings - Fork 34.6k
Description
Version
24.13.0
Platform
Have tried on these:
> Linux [hostname] 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux
> Linux [hostname] 6.12.64-87.122.amzn2023.aarch64 #1 SMP Mon Jan 12 22:17:48 UTC 2026 aarch64 aarch64 aarch64 GNU/Linux
Subsystem
tls
What steps will reproduce the bug?
This is reproducible against mail.smtp2go.com on port 465.
Save the following as test.js and run with node test.js. After socket.end() is called, the process terminates due to an unhandled 'error' event emitted by TLSSocket during TLS teardown.
const tls = require('tls');
const socket = tls.connect(465, 'mail.smtp2go.com', () => {
console.log('TLS connected');
socket.on('data', d => console.log('DATA:', d.toString()));
socket.on('end', () => console.log('end'));
socket.on('finish', () => console.log('finish'));
setTimeout(() => {
socket.end();
console.log('socket.end() called');
}, 3000);
});
setInterval(() => console.log('alive'), 1000);
How often does it reproduce? Is there a required condition?
Every time, when the peer sends invalid (non‑TLS) after (or during?) TLS teardown.
What is the expected behavior? Why is that the expected behavior?
After tls.connect() completes and socket.end() is called, I expected the process to continue running. Instead, the process exited with an "Unhandled 'error' event".
I am not certain whether this behavior is intentional, especially in light of the recent Node 24.13.0 security release, or an edge case in the TLS socket lifecycle.
What do you see instead?
$ node test.js
TLS connected
DATA: 220 mail.smtp2go.com ESMTP Exim 4.99.1-S2G Sat, 07 Feb 2026 05:41:32 +0000
alive
alive
alive
socket.end() called
finish
node:events:486
throw er; // Unhandled 'error' event
^
Error: C0686C2E10700000:error:0A0001BB:SSL routines:tls13_validate_record_header:bad record type:../deps/openssl/openssl/ssl/record/methods/tls13_meth.c:258:
Emitted 'error' event on TLSSocket instance at:
at TLSSocket._emitTLSError (node:_tls_wrap:1050:10)
at TLSWrap.onerror (node:_tls_wrap:491:11) {
library: 'SSL routines',
reason: 'bad record type',
code: 'ERR_SSL_BAD_RECORD_TYPE'
}
Node.js v24.13.0
Additional information
To better understand the peer behavior involved, I verified the server interaction using OpenSSL.
Running the command openssl s_client -connect mail.smtp2go.com:465 -quiet followed by "QUIT" produced:
...
220 mail.smtp2go.com ESMTP Exim 4.99.1-S2G Sat, 07 Feb 2026 04:38:41 +0000
QUIT
221 mail.smtp2go.com closing connection
I also tested against a different SMTP server on port 465, which did not exhibit this behavior and it did not trigger the unhandled 'error' event in Node.
For additional context, I captured debug output using:
NODE_DEBUG=tls,net,stream node test.js
output
$ NODE_DEBUG=tls,net,stream node test.js
TLS 252547: client _init handle? true
NET 252547: pipe false undefined
NET 252547: connect: find host mail.smtp2go.com
NET 252547: connect: dns options { family: undefined, hints: 32 }
NET 252547: connect: autodetecting
TLS 252547: client initRead handle? true buffered? false
STREAM 252547: read 0
STREAM 252547: need readable false
STREAM 252547: length less than watermark true
STREAM 252547: do read
NET 252547: _read - n 65536 isConnecting? true hasHandle? true
NET 252547: _read wait for connection
NET 252547: connect/multiple: will try the following addresses [
...
]
NET 252547: connect/multiple: attempting to connect to 173.255.233.87:465 (addressType: 4)
NET 252547: connect/multiple: setting the attempt timeout to 250 ms
NET 252547: connect/multiple: connection attempt to 173.255.233.87:465 completed with status 0
NET 252547: afterConnect
TLS 252547: client _start handle? true connecting? false requestOCSP? false
NET 252547: _read - n 65536 isConnecting? false hasHandle? true
NET 252547: Socket._handle.readStart
STREAM 252547: read 0
STREAM 252547: need readable true
STREAM 252547: length less than watermark true
STREAM 252547: reading, ended or constructing false
TLS 252547: client onhandshakedone
TLS 252547: client _finishInit handle? true alpn false servername false
TLS 252547: client emit secureConnect. authorized: true
TLS connected
STREAM 252547: resume
STREAM 252547: resume true
STREAM 252547: flow
STREAM 252547: read undefined
STREAM 252547: need readable true
STREAM 252547: length less than watermark true
STREAM 252547: reading, ended or constructing false
STREAM 252547: push <Buffer ...>
DATA: 220 mail.smtp2go.com ESMTP Exim 4.99.1-S2G Sat, 07 Feb 2026 05:54:18 +0000
STREAM 252547: maybeReadMore read 0
STREAM 252547: read 0
STREAM 252547: need readable true
STREAM 252547: length less than watermark true
STREAM 252547: do read
NET 252547: _read - n 65536 isConnecting? false hasHandle? true
alive
alive
alive
NET 252547: _final: not ended, call shutdown()
socket.end() called
NET 252547: afterShutdown destroyed=false
finish
TLS 252547: client onerror [Error: C068302354700000:error:0A0001BB:SSL routines:tls13_validate_record_header:bad record type:../deps/openssl/openssl/ssl/record/methods/tls13_meth.c:258:
] {
library: 'SSL routines',
reason: 'bad record type',
code: 'ERR_SSL_BAD_RECORD_TYPE'
} had? false
node:events:486
throw er; // Unhandled 'error' event
^
Error: C068302354700000:error:0A0001BB:SSL routines:tls13_validate_record_header:bad record type:../deps/openssl/openssl/ssl/record/methods/tls13_meth.c:258:
Emitted 'error' event on TLSSocket instance at:
at TLSSocket._emitTLSError (node:_tls_wrap:1050:10)
at TLSWrap.onerror (node:_tls_wrap:491:11) {
library: 'SSL routines',
reason: 'bad record type',
code: 'ERR_SSL_BAD_RECORD_TYPE'
}
Node.js v24.13.0