CVE-2026-119188: Forge: Denial of service in TLS record processing via a record interleaved with a fragmented handshake message

Published Oct 29, 2026
·
Updated

Summary

A connection created with forge.tls.createConnection() throws an uncaught TypeError from process() when it receives a record of another content type while waiting for the rest of a handshake message that was split across records. A peer can trigger this with 18 bytes before the handshake, without authentication, which terminates Node.js processes that use the documented socket wiring. Fixed in node-forge 1.4.1.

Details

In lib/tls.js, readRecord() handles a record that arrives while a handshake message split across records is incomplete. If the record has any other content type (changecipherspec, alert, applicationdata or heartbeat), forge correctly reports "Invalid fragmented record." through c.error() with a fatal unexpectedmessage alert. That fatal error closes and resets the connection, which sets c.record to null. readRecord() then continues with c.record.ready = true and throws TypeError: Cannot set properties of null (setting 'ready') out of process(). The code is unchanged since the first release.

RFC 5246 section 6.2.1 allows a handshake message to be fragmented across records, and RFC 8446 section 5.1 forbids interleaving handshake messages with other record types. Failing the connection with unexpectedmessage is the intended behavior; the bug is the crash after the error.

node-forge reports TLS protocol errors through the error callback, so applications do not normally wrap process() in try/catch. When process() is called from a Node.js socket data handler, as in the documented usage, the exception is uncaught and terminates the process.

The fix returns from readRecord() right after the fatal error. The connection is failed, the alert is sent and the error callback is called as before, and process() no longer throws.

Patches Fixed in node-forge 1.4.1. The connection still fails with a fatal unexpectedmessage alert and the error callback, but process() no longer throws.

Workarounds Wrap every call to connection.process() in try/catch. The connection has already been failed and closed when the exception is thrown, so the exception can be ignored or the socket destroyed.

Proof of concept

Input (server mode), two records, 18 bytes:

16 03 01 00 06 01 00 00 10 03 01 handshake record: ClientHello header announcing 16 bytes, 2 present 15 03 01 00 02 02 28 alert record

// c = forge.tls.createConnection({server: true, ...}) c.process(forge.util.hexToBytes('1603010006010000100301' + '15030100020228'));

On 1.4.0 the error callback receives "Invalid fragmented record.", then process() throws TypeError: Cannot set properties of null (setting 'ready'). A changecipherspec, applicationdata or heartbeat record in place of the alert has the same effect, and a client connection behaves the same with a fragment of a ServerHello. In a Node.js server that calls c.process(data.toString('binary')) from socket.on('data', ...), a client sending these 18 bytes terminates the server process. On 1.4.1 the connection fails with a fatal unexpectedmessage alert and process() returns normally.

Regression tests in tests/unit/tls.js, "fragmented handshake messages": each of the four other record types after a handshake fragment, in server and client mode, plus same-type continuation records that are still accepted.

Impact

Applications that use node-forge's TLS implementation: connections from forge.tls.createConnection(), including those created by forge.tls.wrapSocket() and the forge.http / forge.xhr TLS connections. Any peer that can connect to a forge TLS server, or any server a forge TLS client connects to, can send 18 bytes before the handshake, without authentication. In Node.js applications using the documented usage, the uncaught exception terminates the process, which drops every connection it serves, and the attacker can repeat it on every restart. There is no confidentiality or integrity impact.

Other sources

Forge (also called node-forge) is a native implementation of Transport Layer Security in JavaScript. Prior to 1.4.1, the affected implementation used forge.tls.createConnection(), fragmented handshake message, interleaved record to process the relevant input or security decision. node-forge continued processing after a TLS record of another content type interrupted a fragmented handshake message. A remote peer could trigger an uncaught TypeError in process(), causing the connection or hosting process to fail. This issue is fixed in version 1.4.1.

— NVD

Affected Software

2 affected componentsFixes available
npm/node-forge<=1.4.0
1.4.1
npm/node-forge<1.4.1
1.4.1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/node-forge to a version that resolves this vulnerability.

    Fixed in 1.4.1
  2. Upgrade

    Upgrade node-forge to a version that resolves this vulnerability.

    Fixed in 1.4.1
  3. Compensating control

    Wrap every call to connection.process() in try/catch when using node-forge TLS connections.

Event History

Oct 29, 2026
CVE Published
via MITRE·07:21 PM
Data Sourced
via MITRE·07:21 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·08:17 PM
DescriptionSeverityWeakness
Oct 30, 2026
Data Sourced
via OSV·12:00 AM
DescriptionSeverityAffected Software
Advisory Published
via GitHub·11:02 PM
Data Sourced
via GitHub·11:02 PM
DescriptionSeverityWeaknessAffected Software
Data Sourced
via OSV·11:02 PM
Weakness

Frequently Asked Questions

1

Which deployments are exposed to this denial of service?

Node.js processes using node-forge TLS connections created with forge.tls.createConnection() and the documented socket wiring are exposed. A malformed peer can terminate the process rather than only closing its own TLS connection.

2

Does exploitation require authentication or a valid TLS session?

No. A peer can trigger the condition before the TLS handshake with 18 bytes, and no authentication is required.

3

What traffic pattern triggers the crash?

The peer must cause a handshake message to be fragmented across TLS records, then send a record with a different content type while Forge is waiting for the remaining handshake fragment. The interleaved record may be change_cipher_spec, alert, application_data, or heartbeat.

4

What version contains the fix?

The issue is fixed in node-forge 1.4.1. The affected code had been unchanged since the first release.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203