CVE-2026-21713
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. Since Node.js 15.0.0, its crypto module has included an implementation of the standard Web Crypto API, exposed as crypto.webcrypto. The cryptographic work behind it, including HMAC signing and verification, is done in Node.js's native C++ layer.
A timing side-channel vulnerability (CVE-2026-21713) has been identified in Node.js's Web Crypto HMAC verification. When subtle.verify() checks a caller-supplied HMAC signature, it should compare the expected and provided values in constant time, so the duration reveals nothing about how much of the signature was right. However, Node.js compared them with memcmp(), which typically stops at the first differing byte. Verification therefore takes slightly longer the more leading bytes are correct. An attacker who can measure that difference precisely enough could use it as an oracle to work out a valid HMAC one byte at a time and forge a message authentication code.
This behaviour maps to CWE-208 (Observable Timing Discrepancy), where two operations take measurably different amounts of time in a way that reveals security-relevant information. In Node.js, the comparison's running time depends on the length of the matching prefix between the computed and supplied MAC. The Node.js project notes that timing-safe comparison was already used elsewhere in the codebase, so this was an oversight rather than a design choice.
Exploitation requires an application that verifies attacker-supplied HMAC signatures with the Web Crypto API (subtle.verify() with an HMAC key, or KMAC on lines that support it). The attacker must also be able to submit many guesses and time each verification at high resolution, typically from the same host or a very low-latency network position. Applications that compute HMACs with crypto.createHmac() and compare them with crypto.timingSafeEqual() do not use this code path. The Node.js project describes the issue as affecting its supported 20.x, 22.x, 24.x and 25.x lines. The same comparison is also present in every End-of-Life line from 15.0.0, when Web Crypto was introduced.
Details
Module Info
- Product: Node.js
- Affected packages: node (built-in crypto module, Web Crypto API; src/crypto/crypto_hmac.cc)
- Affected versions: >=15.0.0 <=15.14.0 >=16.0.0 <=16.20.2 >=17.0.0 <=17.9.1 >=18.0.0 <=18.20.8 >=19.0.0 <=19.9.0 >=20.0.0 <20.20.2 >=21.0.0 <=21.7.3 >=22.0.0 <22.22.2 >=23.0.0 <=23.11.1 >=24.0.0 <24.14.1 >=25.0.0 <25.8.2
- 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 20.20.2, 22.22.2, 24.14.1, and 25.8.2 (upstream fixes, released March 24, 2026); Node.js NES v22.22.3 (22.x line, shipped March 25, 2026), v18.20.16 (18.x line, shipped March 30, 2026), v16.20.11 (16.x line, shipped April 3, 2026), and v20.20.3 (20.x line, shipped June 25, 2026), the 16.x and 18.x builds being for lines that never received an upstream fix before reaching End-of-Life
Vulnerability Info
This Medium-severity vulnerability is found in the HMAC verify path of Node.js's Web Crypto implementation (src/crypto/crypto_hmac.cc). The HackerOne CNA assigns a CVSS v3.0 score of 5.9, and the Node.js project also rates it Medium.
When subtle.verify() is called with an HMAC key, Node.js computes the MAC over the data and is supposed to report a match only if it equals the supplied signature, with timing that is independent of the contents. In the vulnerable implementation, after checking that the lengths match, it compared the two buffers with memcmp(), whose running time depends on where the first difference occurs. The fix replaces memcmp() with OpenSSL's CRYPTO_memcmp(), a constant-time comparison. On 24.x and 25.x, it also covers the KMAC verify path. It shipped as commit cfb51fa9ce on 20.x, 52a52ef619 on 22.x, cc0910c62e on 24.x and 0f9332a40a on 25.x, through nodejs-private pull requests #822 and #831.
An attacker would need an endpoint that verifies HMACs they supply through Web Crypto, enough requests to run a byte-by-byte search, and clock resolution fine enough to see a difference of a few CPU cycles per byte.
Note: Because the timing differences are tiny and network jitter usually swamps them, remote exploitation over ordinary internet links is unlikely. The risk is highest for co-located attackers or very low-latency paths.
Mitigation
Node.js 22.x and 24.x are still supported and are fixed in 22.22.2 and 24.14.1 and later. Node.js 25.x reached End-of-Life on June 1, 2026, so the fix in 25.8.2 is the last for that line. Node.js 20.x reached End-of-Life on April 30, 2026, after its fix in 20.20.2. The 15.x, 16.x, 17.x, 18.x, 19.x, 21.x and 23.x lines never received an upstream fix. Node.js 15.x reached End-of-Life on June 1, 2021; 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 21.x on June 1, 2024; and Node.js 23.x on June 1, 2025. For more information see here.
Users of the affected components should apply one of the following mitigations:
- Upgrade to Node.js 22.22.2 or later on the 22.x line, or to 24.14.1 or later on the 24.x line, 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
- x_probe (reporter)
- Filip Skokan (remediation developer)