CVE-2026-119187
Forge: Denial of service in TLS record processing via call stack exhaustion
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
Forge: Denial of service in TLS record processing via call stack exhaustion
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
- Record
CVE-2026-119187- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-674
- Updated
- 2026-11-04
EUVDEUVD-2026-113364
7.5
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
- Record
EUVD-2026-113364- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-04
GitHub AdvisoriesGHSA-hqq3-7jhf-c5jx
7.5
Forge: Denial of service in TLS record processing via call stack exhaustion
Summary
Connections created with forge.tls.createConnection() processed received TLS records recursively, one stack level per record. A peer can send one chunk of thousands of small records, such as heartbeat records, which are accepted before the handshake, and process() throws RangeError: Maximum call stack size exceeded, which terminates Node.js processes that use the documented socket wiring. Fixed in node-forge 1.4.1.
Details
In lib/tls.js, c.process() reads one record and passes it to _update(), which calls the handler for the record type from ctTable. Every handler (tls.handleHeartbeat, tls.handleApplicationData, tls.handleHandshake for fragmented messages, tls.handleHelloRequest and the other handshake handlers) ends by calling c.process() again to continue with the next buffered record, or the next message in the same record. Each record therefore adds process → _update → handler to the call stack. In Node.js 24, about 2,300 eight-byte records (under 20 KB) in one chunk are enough for process() to throw RangeError: Maximum call stack size exceeded.
ctTable maps heartbeat records to tls.handleHeartbeat in every client and server state, so heartbeat records are processed before the handshake without any extension negotiation. The attack needs no authentication and no valid handshake messages. Both server connections (attacked by a client) and client connections (attacked by the server they connect to) are affected. Other record types recurse the same way: a handshake message fragmented over many records, many HelloRequest messages in one record, or many application data records after the handshake.
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. If the exception is caught, the connection is left partially processed and should be discarded.
No specification is violated; this is an implementation flaw (uncontrolled recursion).
The fix makes c.process() iterative. The record-reading code moves into _processRecord(), and c.process() runs it in a loop. A handler's call to c.process() without new data, made while records are being processed, now only flags that the loop should continue. Calls with new data are processed right away as before, so callback order and return values are unchanged.
Patches
Fixed in node-forge 1.4.1. Records are now processed in a loop, so the stack depth no longer depends on the number of records.
Workarounds
Wrap every call to connection.process() in try/catch, and on an exception close the connection (connection.close()) and destroy the underlying socket. This prevents the process crash but not the loss of the attacked connection.
Credits
Reported jointly by Ziyue Wang, Chenchen, Strick Sheng, Liyi Zhou, and Maurice Ng.
Proof of concept
Input: one chunk of N identical heartbeat records, each 8 bytes:
18 03 01 00 03 01 00 00 (content type 24 = heartbeat, TLS 1.0, length 3, heartbeat_request with a 0-byte payload)
// c = forge.tls.createConnection({server: true, ...}) var rec = forge.util.hexToBytes('1803010003010000'); c.process(new Array(5001).join(rec)); // 5,000 records, 40,000 bytes
On 1.4.0 (Node.js 24), process() throws RangeError: Maximum call stack size exceeded after about 2,300 records, before any handshake. The same happens for a client connection. In a Node.js server that calls c.process(data.toString('binary')) from socket.on('data', ...), a client sending these 40,000 bytes terminates the server process. On 1.4.1 all records are processed and the server keeps running.
Regression tests in tests/unit/tls.js, "record processing": 50,000 heartbeat records in one call in server and client mode, a handshake message fragmented over 50,000 records,…
- Record
GHSA-hqq3-7jhf-c5jx- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-674
- Updated
- 2026-11-02
GitHub AdvisoriesGHSA-gf8q-jrpm-jvxq No score
URL parsing in node-forge could lead to undesired behavior.
Impact
The regex used for the forge.util.parseUrl API would not properly parse certain inputs resulting in a parsed data structure that could lead to undesired behavior.
Patches
forge.util.parseUrl and other very old related URL APIs were removed in 1.0.0 in favor of letting applications use the more modern WHATWG URL Standard API.
Workarounds
Ensure code does not directly or indirectly call forge.util.parseUrl with untrusted input.
References
For more information
If you have any questions or comments about this advisory:
- Open an issue in forge
- Email us at [email protected]
- Record
GHSA-gf8q-jrpm-jvxq- Weakness
- CWE-601
- Updated
- 2026-11-02
NVD
7.5
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
- Record
CVE-2026-119187- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-674
- Updated
- 2026-11-04
OSV
7.5
Forge: Denial of service in TLS record processing via call stack exhaustion
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
- Record
CVE-2026-119187- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-674
- Updated
- 2026-11-07
Show 10 moreShow less
OSVGHSA-hqq3-7jhf-c5jx
7.5
Forge: Denial of service in TLS record processing via call stack exhaustion
Summary
Connections created with forge.tls.createConnection() processed received TLS records recursively, one stack level per record. A peer can send one chunk of thousands of small records, such as heartbeat records, which are accepted before the handshake, and process() throws RangeError: Maximum call stack size exceeded, which terminates Node.js processes that use the documented socket wiring. Fixed in node-forge 1.4.1.
Details
In lib/tls.js, c.process() reads one record and passes it to _update(), which calls the handler for the record type from ctTable. Every handler (tls.handleHeartbeat, tls.handleApplicationData, tls.handleHandshake for fragmented messages, tls.handleHelloRequest and the other handshake handlers) ends by calling c.process() again to continue with the next buffered record, or the next message in the same record. Each record therefore adds process → _update → handler to the call stack. In Node.js 24, about 2,300 eight-byte records (under 20 KB) in one chunk are enough for process() to throw RangeError: Maximum call stack size exceeded.
ctTable maps heartbeat records to tls.handleHeartbeat in every client and server state, so heartbeat records are processed before the handshake without any extension negotiation. The attack needs no authentication and no valid handshake messages. Both server connections (attacked by a client) and client connections (attacked by the server they connect to) are affected. Other record types recurse the same way: a handshake message fragmented over many records, many HelloRequest messages in one record, or many application data records after the handshake.
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. If the exception is caught, the connection is left partially processed and should be discarded.
No specification is violated; this is an implementation flaw (uncontrolled recursion).
The fix makes c.process() iterative. The record-reading code moves into _processRecord(), and c.process() runs it in a loop. A handler's call to c.process() without new data, made while records are being processed, now only flags that the loop should continue. Calls with new data are processed right away as before, so callback order and return values are unchanged.
Patches
Fixed in node-forge 1.4.1. Records are now processed in a loop, so the stack depth no longer depends on the number of records.
Workarounds
Wrap every call to connection.process() in try/catch, and on an exception close the connection (connection.close()) and destroy the underlying socket. This prevents the process crash but not the loss of the attacked connection.
Credits
Reported jointly by Ziyue Wang, Chenchen, Strick Sheng, Liyi Zhou, and Maurice Ng.
Proof of concept
Input: one chunk of N identical heartbeat records, each 8 bytes:
18 03 01 00 03 01 00 00 (content type 24 = heartbeat, TLS 1.0, length 3, heartbeat_request with a 0-byte payload)
// c = forge.tls.createConnection({server: true, ...}) var rec = forge.util.hexToBytes('1803010003010000'); c.process(new Array(5001).join(rec)); // 5,000 records, 40,000 bytes
On 1.4.0 (Node.js 24), process() throws RangeError: Maximum call stack size exceeded after about 2,300 records, before any handshake. The same happens for a client connection. In a Node.js server that calls c.process(data.toString('binary')) from socket.on('data', ...), a client sending these 40,000 bytes terminates the server process. On 1.4.1 all records are processed and the server keeps running.
Regression tests in tests/unit/tls.js, "record processing": 50,000 heartbeat records in one call in server and client mode, a handshake message fragmented over 50,000 records,…
- Record
GHSA-hqq3-7jhf-c5jx- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-674
- Updated
- 2026-11-02
OSVROOT-APP-NPM-CVE-2026-119187
7.5
CVE-2026-119187 in node-forge - Patched by Root
Root has patched CVE-2026-119187 in the node-forge package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-CVE-2026-119187- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-06
OSVUBUNTU-CVE-2026-119187
7.5
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
- Record
UBUNTU-CVE-2026-119187- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-05
OSVAZL-112472 No score
CVE-2026-119187 affecting package python-tensorboard 2.16.2-6
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(), TLS record processing, process() to process the relevant input or security decision. node-forge processed received TLS records recursively, consuming one JavaScript stack frame per record in a single input chunk. A remote peer could send thousands of small records together and exhaust the call stack, causing an uncaught exception and denial of service. This issue is fixed in version 1.4.1.
- Record
AZL-112472- Updated
- 2026-11-05
OSVCLSA-2026-1793790288 No score
TuxCare security update for node-forge (10 CVEs)
TuxCare rebuilt node-forge to address 10 CVEs. Fixed in 1.3.3-tuxcare.3.
- Record
CLSA-2026-1793790288- Updated
- 2026-11-04
OSVCLSA-2026-1793801784 No score
TuxCare security update for node-forge (6 CVEs)
TuxCare rebuilt node-forge to address 6 CVEs. Fixed in 1.3.1-tuxcare.2.
- Record
CLSA-2026-1793801784- Updated
- 2026-11-04
OSVCLSA-2026-1793808759 No score
TuxCare security update for node-forge (6 CVEs)
TuxCare rebuilt node-forge to address 6 CVEs. Fixed in 0.10.0-tuxcare.8.
- Record
CLSA-2026-1793808759- Updated
- 2026-11-04
OSVCLSA-2026-1793814373 No score
TuxCare security update for node-forge (8 CVEs)
TuxCare rebuilt node-forge to address 8 CVEs. Fixed in 0.9.0-tuxcare.1.
- Record
CLSA-2026-1793814373- Updated
- 2026-11-05
OSVGHSA-gf8q-jrpm-jvxq No score
URL parsing in node-forge could lead to undesired behavior.
Impact
The regex used for the forge.util.parseUrl API would not properly parse certain inputs resulting in a parsed data structure that could lead to undesired behavior.
Patches
forge.util.parseUrl and other very old related URL APIs were removed in 1.0.0 in favor of letting applications use the more modern WHATWG URL Standard API.
Workarounds
Ensure code does not directly or indirectly call forge.util.parseUrl with untrusted input.
References
For more information
If you have any questions or comments about this advisory:
- Open an issue in forge
- Email us at [email protected]
- Record
GHSA-gf8q-jrpm-jvxq- Weakness
- CWE-601
- Updated
- 2026-11-02
OSVROOT-APP-NPM-GHSA-gf8q-jrpm-jvxq No score
GHSA-gf8q-jrpm-jvxq in node-forge - Patched by Root
Root has patched GHSA-gf8q-jrpm-jvxq in the node-forge package for Root:npm. Multiple fixed versions available.
- Record
ROOT-APP-NPM-GHSA-gf8q-jrpm-jvxq- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
node-forgenpm |
before 1.0.0 | 1.0.0 |
node-forgenpm |
through 1.4.0 | 1.4.1 |
python-tensorboardAzure Linux:3 |
through 2.16.2-6 | None known |
node-forgeTuxCare:npm From an advisory covering 10 CVEs |
1.3.3-tuxcare.0 up to 1.3.3-tuxcare.3, plus listed versions 1.3.31.3.3-tuxcare.11.3.3-tuxcare.2 |
1.3.3-tuxcare.3 |
node-forgeTuxCare:npm From an advisory covering 6 CVEs |
1.3.1-tuxcare.0 up to 1.3.1-tuxcare.2, plus listed versions 1.3.11.3.1-tuxcare.1 |
1.3.1-tuxcare.2 |
node-forgeTuxCare:npm From an advisory covering 6 CVEs |
0.10.0-tuxcare.0 up to 0.10.0-tuxcare.8, plus listed versions 0.10.00.10.0-tuxcare.10.10.0-tuxcare.20.10.0-tuxcare.30.10.0-tuxcare.40.10.0-tuxcare.50.10.0-tuxcare.60.10.0-tuxcare.7 |
0.10.0-tuxcare.8 |
node-forgeTuxCare:npm From an advisory covering 7 CVEs |
0.9.0-tuxcare.0 up to 0.9.0-tuxcare.1, plus listed versions 0.9.0 |
0.9.0-tuxcare.1 |
node-forgenpm |
before 1.4.1 | 1.4.1 |
node-forgeRoot:npm |
before 1.4.0-aikido.5 | 1.4.0-aikido.51.3.3-aikido.6 |
@rootio/node-forgeRoot:npm |
before 1.4.0-root.io.5 | 1.4.0-root.io.51.3.3-root.io.6 |
Show 4 moreShow less
| Package | Affected | Fixed |
|---|---|---|
node-forgeRoot:npm |
before 1.0.0-aikido.1 | 1.0.0-aikido.1 |
@rootio/node-forgeRoot:npm |
before 1.0.0-root.io.1 | 1.0.0-root.io.1 |
node-node-forgeUbuntu:20.04:LTS |
All versions, plus listed versions 0.8.5~dfsg-20.9.1~dfsg-1 |
None known |
node-node-forgeUbuntu:22.04:LTS |
All versions, plus listed versions 0.10.0~dfsg-31.2.1~dfsg-2 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | ||
| affected | OSV | |
| affected, aliases, cwes, published, references | OSV | |
| affected, aliases | OSV | |
| affected, aliases | EUVD, NVD, OSV | |
| facts, references | CVE List | |
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-119187 is a high vulnerability (CVSS 7.5) in Digitalbazaar Forge, published January 8, 2022. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.41%, the 36th percentile. Fixed in node-forge 1.0.0.
References
github.com/digitalbazaar/forge/security/advisories/GHSA-hqq3-7jhf-c5jx
github.com/digitalbazaar/forge/commit/817e2ce0d0f6d8a25bc9c2670615c38a9ffdc51c
github.com/digitalbazaar/forge/releases/tag/v1.4.1
github.com/digitalbazaar/forge/security/advisories/GHSA-gf8q-jrpm-jvxq
nvd.nist.gov/vuln/detail/CVE-2022-0122
huntr.dev/bounties/41852c50-3c6d-4703-8c55-4db27164a4ae
Show 7 moreShow less
github.com/advisories/GHSA-gf8q-jrpm-jvxq
nvd.nist.gov/vuln/detail/CVE-2026-119187
github.com/advisories/GHSA-hqq3-7jhf-c5jx
github.com/CVEProject/cvelistV5/tree/main/cves/2026/119xxx/CVE-2026-119187.json
github.com/digitalbazaar/forge
ubuntu.com/security/CVE-2026-119187
cve.org/CVERecord?id=CVE-2026-119187
Left out here: the rest of 2 source descriptions. The JSON record has them.