TLSSocket does not gracefully handle peer protocol violation during TLS teardown
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- JavaScript
- Star
- 122k
- Fork
- 37.4k
- Merge trung bình
- 4 ngày 3 giờ
- Pull request đã merge (30 ngày)
- 272
Mô tả
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
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu với trình tái hiện test.js được cung cấp và trace teardown TLS, sau đó kiểm tra các vị trí node:_tls_wrap được hiển thị trong stack và đầu ra debug. Xác định cách bản ghi không hợp lệ của peer được xử lý sau socket.end() và xác minh hành vi bằng reproduction của mail.smtp2go.com. Hoàn tất khi teardown không còn gây ra lỗi TLSSocket chưa được xử lý và kịch bản được báo cáo vẫn được bao phủ bởi một regression test.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- javascript, nodejs
- Lĩnh vực
- networking, security
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 50/100