CVE-2024-13176
Patch Available.
This Vulnerability has been fixed in the Never-Ending Support (NES) version offered by HeroDevs.
Overview
Node.js is an asynchronous, event-driven JavaScript runtime designed for building scalable network applications. The official Node.js distributions do not link against a system cryptography library: they compile and ship their own copy of OpenSSL at deps/openssl in the Node.js source tree, and the built-in crypto and tls modules are bindings over that bundled copy. A vulnerability in the bundled OpenSSL therefore affects Node.js directly, whether or not Node.js itself contains any new code.
A timing side-channel vulnerability (CVE-2024-13176) has been identified in the ECDSA signing code of the OpenSSL library bundled with Node.js. To produce an ECDSA signature, OpenSSL inverts a secret per-signature nonce, and that step is supposed to take the same time whatever the nonce's value. However, when the top word of the inverted nonce is zero, the computation runs about 300 nanoseconds faster. An attacker who can measure enough signatures this precisely could use the leak to recover the signer's private key.
This behaviour maps to CWE-385 (Covert Timing Channel), where information is conveyed by modulating some aspect of system behaviour over time so that an observer can infer protected data. In OpenSSL, the modular exponentiation used for the nonce inversion trims leading zero words from its result, so the time a signature takes depends on secret data. Nonce leaks of this kind are a classic route to recovering ECDSA private keys.
Exploitation requires an attacker who can trigger many ECDSA signatures with the same key and time each one to sub-microsecond precision. In practice, that means code on the same physical machine as the signing process, or a very fast, low-latency network link to it. The signal appears with significant probability only on some curves, notably NIST P-521, so Node.js applications that sign with P-521 keys are the ones at risk. That covers crypto.sign() and crypto.createSign(), and TLS servers presenting a P-521 ECDSA certificate. This issue affects every Node.js release line up to 17.x, 19.x and 21.x, and 18.x, 20.x, 22.x and 23.x before the versions listed above.
Details
Module Info
- Product: Node.js
- Affected packages: node (bundles OpenSSL under deps/openssl)
- Affected versions: <=17.9.1 >=18.0.0 <18.20.8 >=19.0.0 <=19.9.0 >=20.0.0 <20.19.5 >=21.0.0 <=21.7.3 >=22.0.0 <22.15.0 >=23.0.0 <23.10.0
- 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 23.10.0 (March 13, 2025), 18.20.8 (March 27, 2025), 22.15.0 (April 23, 2025) and 20.19.5 (September 3, 2025), upstream releases whose bundled OpenSSL includes the fix; Node.js NES v18.20.13 (NES 18.x line, shipped August 27, 2025), which updated OpenSSL to 3.0.16; Node.js 24.0.0 and later are not affected
Vulnerability Info
This Medium-severity vulnerability is found in the ECDSA nonce-inversion path of the OpenSSL library that Node.js bundles at deps/openssl, in every Node.js release whose bundled OpenSSL predates 3.0.16 or lacks the equivalent backport. The CISA ADP assigns a CVSS v3.1 score of 4.1; NVD has not published its own score.
During ECDSA signing, OpenSSL computes the inverse of the secret nonce modulo the curve order using Fermat's little theorem. Its ec_field_inverse_mod_ord() routine does this with a Montgomery modular exponentiation. That routine is supposed to keep the result at a fixed width. In the vulnerable implementation, it called BN_mod_exp_mont(), which normalizes the result and drops a leading zero word. The rest of the signing computation then runs measurably faster for those nonces. The fix introduces bn_mod_exp_mont_fixed_top(), which keeps the result fixed-width, and uses it for the inversion. See the OpenSSL 3.0 fix commit for the exact change.
An attacker would need to collect timing measurements for a large number of signatures made with the victim's key. Typically that means co-located code, such as another tenant on the same host, or a very low-latency network position against a service that signs on request.
Note: Because the signal is only likely on some curves, such as P-521, applications that sign only with P-256 or P-384 keys, or that do not use ECDSA, face a much smaller risk.
Mitigation
Node.js 23.x reached End-of-Life on June 1, 2025, so the fix in 23.10.0 is the last for that line. Node.js 22.x is still supported and is fixed in 22.15.0 and later. All other affected Node.js release lines are past their support window and will not receive further upstream updates. Node.js 12.x reached End-of-Life on April 30, 2022; Node.js 14.x on April 30, 2023; Node.js 16.x on September 11, 2023; Node.js 17.x on June 1, 2022; Node.js 18.x on April 30, 2025; Node.js 19.x on June 1, 2023; Node.js 20.x on April 30, 2026; and Node.js 21.x on June 1, 2024. For more information see here.
Users of the affected components should apply one of the following mitigations:
- Upgrade to Node.js 22.15.0 or later on the 22.x line, or to Node.js 24.x, both of which include this fix.
- Migrate affected applications away from the End-of-Life Node.js release lines.
- Leverage a commercial support partner like HeroDevs for post-EOL security support, through Node.js NES.
Credits
- George Pantelakis from Red Hat (finder)
- Alicja Kario from Red Hat (finder)
- Tomáš Mráz (remediation developer)