CVE-2022-4304
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. It uses an event-driven, non-blocking I/O model and is widely used for web applications and server-side development. Node.js compiles its own copy of OpenSSL from deps/openssl in the Node.js source tree, and the built-in crypto, tls and https modules, including crypto.privateDecrypt() and RSA key exchange in TLS, sit on top of that bundled copy.
A vulnerability (CVE-2022-4304) has been identified in the OpenSSL library bundled with Node.js. The time OpenSSL takes to finish an RSA decryption varies with the decrypted value, and that variation can be measured across a network. An attacker who can submit a very large number of chosen ciphertexts and time the responses may be able to recover a plaintext in a Bleichenbacher-style attack. All RSA padding modes are affected: PKCS#1 v1.5, RSA-OAEP and RSASVE.
This flaw maps to CWE-203 (Observable Discrepancy), where software behaves measurably differently depending on secret data, letting an outside observer learn about that data. In OpenSSL, the last stage of RSA private-key decryption, which removes the random blinding factor and converts the result to bytes, did not run in constant time. Those timing differences act as an oracle that, queried enough times, reveals the plaintext of an RSA-encrypted message.
The most direct target is TLS with RSA key exchange: a client encrypts the pre-master secret to the server's RSA key, and an attacker who recorded that handshake can replay variations of it to the server, time each response, and eventually recover the pre-master secret and decrypt the recorded session. Node.js servers that negotiate RSA key exchange, and applications that decrypt attacker-supplied data with crypto.privateDecrypt(), are in scope. TLS 1.3 and the ECDHE key exchanges preferred by default do not encrypt the pre-master secret with RSA. This issue affects every Node.js release line from 4.x through 19.x whose bundled OpenSSL is 1.0.2, 1.1.1 or 3.0, up to the versions listed above.
Details
Module Info
- Product: Node.js
- Affected packages: node (bundles OpenSSL under deps/openssl)
- Affected versions: >=4.0.0 <=4.9.1 >=5.0.0 <=5.12.0 >=6.0.0 <=6.17.1 >=7.0.0 <=7.10.1 >=8.0.0 <=8.17.0 >=9.0.0 <=9.11.2 >=10.16.0 <=10.24.1 >=11.9.0 <=11.15.0 >=12.0.0 <=12.22.12 >=13.0.0 <=13.14.0 >=14.0.0 <14.21.3 >=15.0.0 <=15.14.0 >=16.0.0 <16.19.1 >=17.0.0 <=17.9.1 >=18.0.0 <18.14.1 >=19.0.0 <19.6.1
- GitHub repository: https://github.com/nodejs/node
- Published packages: https://nodejs.org/en/download
- Package manager: Not applicable; Node.js is distributed as runtime builds from nodejs.org rather than as a published npm package
- Fixed in: Node.js 14.21.3, 16.19.1, 18.14.1 and 19.6.1 (all February 16, 2023), security releases that upgraded the bundled OpenSSL to 1.1.1t or 3.0.8; Node.js NES v16.20.3 (16.x line, shipped July 30, 2024), a later cumulative build carrying the same fix. The other release lines listed above never received an updated OpenSSL
Vulnerability Info
This Medium-severity vulnerability is found in the OpenSSL library that Node.js bundles and statically links at deps/openssl, in Node.js releases whose bundled OpenSSL predates 1.1.1t, 3.0.8 or 1.0.2zg. NVD assigns a CVSS v3.1 score of 5.9; OpenSSL rates the issue Moderate.
RSA private-key operations in OpenSSL are blinded: the input is multiplied by a random value before the private-key exponentiation and the blinding is removed afterwards, so the exponentiation's timing reveals nothing about the real input. In the vulnerable versions, the step that removed the blinding and turned the result into a fixed-length byte string used general-purpose big-number arithmetic whose running time depended on the value being produced. The fix replaces that step with a new constant-time routine that combines blinding removal and conversion to a fixed-length output. See the OpenSSL fix commit for the exact change.
The attack needs an observed RSA-encrypted message, the ability to send the target a very large number of trial messages, and timing measurements precise enough to separate the cases, which is why NVD rates the attack complexity as high. A successful attack discloses the plaintext; it does not reveal the private key or let the attacker modify data.
Note: Node.js deployments that negotiate only ECDHE or TLS 1.3 key exchange and never decrypt attacker-supplied data with an RSA private key are not exposed by this issue.
Mitigation
Users of the affected components should apply one of the following mitigations:
- Upgrade to a currently supported Node.js LTS release (22.x or 24.x), both of which bundle OpenSSL 3.5, which includes this fix.
- Where an upgrade is not yet possible, disable RSA key-exchange cipher suites so TLS uses ECDHE or TLS 1.3, and avoid decrypting attacker-supplied data with crypto.privateDecrypt().
- Leverage a commercial support partner like HeroDevs for post-EOL security support, through Node.js NES.
Credits
- Hubert Kario from Red Hat (finder, remediation developer)
- Dmitry Belyavsky from Red Hat (remediation developer)