CVE-2026-106069
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. Its tls module, which https and other TLS clients build on, verifies that the server's certificate was issued for the host the client connected to. tls.checkServerIdentity() normalizes the host with the URL parser's domainToASCII() and compares the result with the certificate, while the connection itself is made by net.connect(), which resolves the host through the operating system's resolver.
An improper certificate validation vulnerability (CVE-2026-106069) has been identified in Node.js's TLS hostname verification. The certificate is supposed to be checked against the same address the client is connected to. However, for a non-canonical IPv4 literal with a leading zero, such as 0127.0.0.1, the two sides read the host differently. domainToASCII() follows the WHATWG URL rules, which treat a leading-zero octet as octal, so 0127.0.0.1 becomes 87.0.0.1, and the certificate is checked against 87.0.0.1. The operating system resolver, which on some platforms such as macOS reads the octet as decimal, connects to 127.0.0.1. A server at the connected address can then be authenticated with a certificate issued for another IP address.
This behaviour maps to CWE-295 (Improper Certificate Validation), the weakness assigned in the CVE record, where the product does not validate, or incorrectly validates, a certificate. In Node.js, the certificate is validated, but for an address other than the peer's, so a certificate that is valid for one IP vouches for a server at another.
Exploitation requires a TLS client that connects to a host string the attacker can influence, such as a URL or address taken from input, on a platform whose resolver reads leading-zero octets differently from the WHATWG rules. The attacker also needs a server at the address the resolver picks and a certificate from a CA the client trusts for the address the WHATWG rules produce. Clients that connect to host names or to canonical dotted-decimal addresses are not exposed, and on resolvers that read leading zeros as octal, such as glibc, both readings agree. The Node.js project describes the issue as affecting its supported 22.x, 24.x and 26.x lines. Upstream releases older than the June 2026 fix for CVE-2026-48618 compare the host with the certificate exactly as written and are not affected. The HeroDevs NES builds of the 12.x through 22.x lines carry that normalization and are affected in the same way as 22.x.
Details
Module Info
- Product: Node.js
- Affected packages: node (built-in tls module; lib/tls.js)
- Affected versions: >=22.0.0 <22.23.4, >=24.0.0 <24.22.1, >=26.0.0 <26.12.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 22.23.4, 24.22.1, and 26.12.1; Node.js NES v12.22.21, v14.21.14, v16.20.15, v18.20.20, v20.20.5, v20.20.13, and v22.23.5
Vulnerability Info
This High-severity vulnerability is found in tls.checkServerIdentity() in Node.js's tls module (lib/tls.js). The HackerOne CNA scores it 7.4 (CVSS v3.0) and the Node.js project rates it High; NVD has not yet scored it.
Before it compares the host with the certificate, tls.checkServerIdentity() normalizes it, and on the 22.x line it decides from the normalized form whether the host is an IP address.
domainToASCII('0127.0.0.1') parses the host the way a browser does: the leading 0 marks the octet as octal, so the result is 87.0.0.1. The certificate is then accepted if it carries IP Address:87.0.0.1. Nothing in this check knows where the socket went. net.isIP('0127.0.0.1') is 0, so net.connect() passes the original string to dns.lookup(), and the platform's getaddrinfo() decides the address. On macOS that is 127.0.0.1.
On 24.x and 26.x, the same function decides the IP question from the original string instead and sends 0127.0.0.1 down the DNS-name path. There it is still compared in its normalized form, so a certificate with DNS:87.0.0.1, or a Common Name of 87.0.0.1, is accepted for the connection to 127.0.0.1. Either way, the identity Node.js verifies is not the address it connected to.
Note: The attacker needs a trusted certificate for the address the WHATWG rules produce and must be able to answer at the address the platform resolver produces. Platforms whose resolver also reads leading-zero octets as octal resolve both readings to the same address.
Mitigation
Node.js 22.x, 24.x and 26.x are supported and are fixed in 22.23.4, 24.22.1 and 26.12.1 and later. Every other release line is past its support window and never received an upstream fix; their upstream releases do not contain the affected normalization, but the HeroDevs NES builds of 12.x through 20.x do. 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 18.x on April 30, 2025; and Node.js 20.x on April 30, 2026. For more information see the Node.js previous releases schedule.
Users of the affected components should apply one of the following mitigations:
- Upgrade to Node.js 22.23.4, 24.22.1 or 26.12.1 or later on those lines, all 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
- anagnorisis2peripeteia (reporter)
- Matteo Collina (remediation developer)