Node 24.22.0 accepts 127.1 against a DNS name that 22.23.3 already rejects
127.1 is a spelling glibc resolves to 127.0.0.1. It is not the text 127.0.0.1. On Node.js 24.22.0, a local TLS server whose certificate had only DNS:127.0.0.1 completed the handshake when the client used that short spelling. The same certificate, the same spelling, and the same loopback listener were rejected by Node.js 22.23.3. That error called 127.1 an IP address that was not in the certificate. Node.js 24.22.1 and 22.23.4 rejected it too, with a third message: the host is a non-canonical IP address.
That is not one bug with one fixed version. The 21 October 2026 security release names CVE-2026-106072 for non-canonical IPv4 spellings and says the issue affects 22.x, 24.x, and 26.x. On the four official linux-x64 binaries compared here, acceptance of a DNS name that looks like an address was a 24.22.0 result. 22.23.3 already refused that certificate. What 22.23.3 still allowed, and 22.23.4 stopped, was a different pair: a short spelling plus a certificate that actually had IP Address:127.0.0.1.
The comparison used the official linux-x64 tarballs of 22.23.3, 22.23.4, 24.22.0, and 24.22.1. Each archive matched the SHA-256 line in that release’s SHASUMS256.txt before it was unpacked.
22.23.3 df450af89261115ef9f9e3830c3eeb2cc9213b63c720b1af623cb5dcbe2e02de
22.23.4 1805bcd35e6815559bd2eb97db438d3fdb0eb3a5e6a977b7c1badca76337e9ce
24.22.0 cc2f601cee82d9a5a233302fe307abc600727035fd7d2c3a3571755989e95008
24.22.1 6c172a9ab6718f7b801fb5a7bd486af2ee5e32758086a04b84fcce2aa77095e6
node -v printed the version in the filename. process.versions.openssl printed 3.5.8 on 22.23.3 and 24.22.0, and 3.5.9 on 22.23.4 and 24.22.1. The certificates were minted by the host OpenSSL 3.5.7, valid for one day, self-signed, and discarded. The listener bound only 127.0.0.1. No public host was contacted for the TLS checks. Node.js 26.12.0 and 26.12.1 were not in the set. The host was Debian 13 on Linux amd64.
A DNS name that looks like an address
The first certificate had one subject alternative name, DNS:127.0.0.1, and no IP SAN. Each binary connected to the listener with host and servername set to the same spelling, rejectUnauthorized left true, and that certificate as the only trust anchor. tls.checkServerIdentity was also called with the peer certificate the handshake returned. The two answers agreed on every row.
On 24.22.0 these spellings were a match, and the handshake was authorized:
127.1
127.0.1
0177.0.0.1
0x7f.0.0.1
2130706433
127.0.0.01
127.000.000.001
The two fullwidth forms were authorized on 24.22.0 as well. The advisory lists fullwidth digits as CVE-2026-105483 and says that issue affects 24.x and 26.x, not 22.x. The 22.23.3 binary agreed with that scope. It did not authorize the fullwidth host against this certificate. It reported that the IP was not in the certificate’s list.
The canonical spelling did not follow the short forms. 127.0.0.1 was ERR_TLS_CERT_ALTNAME_INVALID on all four binaries, with the message that the IP was not in the certificate. A check that uses only 127.0.0.1 will record a rejection and miss the spelling 24.22.0 accepts. not-an-ip.example was also rejected on all four, as a hostname that was not in the DNS SAN. That control says the trust anchor was not a blanket accept.
22.23.3 rejected every non-canonical spelling against this DNS-only certificate. The message was IP: 127.1 is not in the cert's list, and the same shape for the octal, hex, integer, padded, and fullwidth forms. It had already classified those strings as IP addresses. It had not matched them to DNS:127.0.0.1. Treating 22.23.3 as affected in the same way as 24.22.0 would invent an acceptance this run did not see.
24.22.1 and 22.23.4 rejected the same spellings with Host is a non-canonical IP address. The code is still ERR_TLS_CERT_ALTNAME_INVALID. A log scraper that looks only for that code cannot tell the three refusals apart. The text after the code says whether the binary treated the spelling as an unknown IP, a DNS mismatch, or a non-canonical address.
An IP SAN is not the same test
The second certificate had IP Address:127.0.0.1 and no DNS SAN. 127.0.0.1 was authorized on all four binaries. That is the expected match, and it shows the listener and the trust anchor were capable of a successful handshake.
22.23.3 also authorized the short, hex, integer, padded, and fullwidth spellings that the resolver mapped to 127.0.0.1. 127.1 completed the handshake. So did 0x7f.0.0.1 and 2130706433. The identity check returned a match, not an error. On this line, a certificate issued for the address was accepted for a spelling of that address.
24.22.0 did not do that. Against the IP SAN, 127.1 failed because the host was not the certificate’s common name. The same hostname-shaped error came back for the octal, hex, integer, padded, and fullwidth forms. The handshake was not authorized. 24.22.0 had treated those strings as DNS names when the certificate contained DNS:127.0.0.1, and it treated them as DNS names again when the certificate contained only an IP SAN. The IP SAN was not the field it compared. Reissuing the certificate with an IP SAN, and leaving the client on 24.22.0, stops the DNS-name acceptance and also stops the short spelling from matching the address it resolves to. Both outcomes are in the 24.22.0 results. Neither is a reason to stay on 24.22.0.
22.23.4 and 24.22.1 refused every non-canonical spelling against the IP SAN, again with Host is a non-canonical IP address. The canonical address still matched. A client that connects with 127.1, 0177.0.0.1, or 127.0.0.01 and depends on an IP SAN will pass on 22.23.3 and fail on 22.23.4. That failure is the security check. It is also a behavior change for any job that was using the short form on purpose. The release notes do not list those spellings as a compatibility note. The handshake does.
0127.0.0.1 was the exception on 22.23.3 even with the IP SAN. Identity said that IP was not in the certificate’s list of 127.0.0.1. The resolver returned 87.0.0.1, and the connect was refused because the test server was not bound to that address. 22.23.3 did not fold that leading-zero form into 127.0.0.1.
The wildcard and the leading zero do not name the socket
A third certificate had DNS:*.0.0.1. On 24.22.0, 127.1 was an identity match and an authorized handshake, the same result as the explicit DNS:127.0.0.1 certificate. 0127.0.0.1 was also an identity match against the wildcard. The socket did not go to the test listener. Every binary resolved 0127.0.0.1 to 87.0.0.1, and the connect was refused because nothing in this test listened on that address. This run did not add a listener there. The identity match is the observation. A completed handshake to the resolved address was not part of the run, and it is not required to see that 24.22.0’s identity answer and the kernel’s destination are different strings.
CVE-2026-106069 describes the other half of that split. WHATWG parsing reads a leading-zero octet as octal, so 0127.0.0.1 becomes 87.0.0.1, while some operating-system resolvers read the same text as decimal 127.0.0.1. This host did not show that decimal reading. The resolver and all four binaries agreed on 87.0.0.1. A fourth certificate, DNS:87.0.0.1, made the identity side of the advisory visible on 24.22.0 only: the identity check for 0127.0.0.1 returned a match. 22.23.3 rejected that host as an IP that was not in the certificate. 22.23.4 and 24.22.1 rejected it as non-canonical. The connect remained a refusal on every binary, because the server was still bound to 127.0.0.1.
The advisory says a macOS resolver can connect to 127.0.0.1 while the identity check is thinking about 87.0.0.1. This run cannot confirm or deny that platform. It can confirm that, on this Linux host, 24.22.0 will call 0127.0.0.1 a match for DNS:87.0.0.1 and for DNS:*.0.0.1, and that the socket for that spelling does not open to the listener bound for the other tests. Do not repeat the connect to the octal address in order to see the identity result. tls.checkServerIdentity and dns.lookup separate those two answers without opening a socket to the resolved address.
Each connect also printed Node’s warning that an IP address is not a valid TLS server name under RFC 6066. The warning did not skip the identity check. The authorized and rejected results above were produced while that warning was printed. A future binary that ignores servername when it is an IP address would be a different test. These four did not do that.
resolve4 still sent the truncated name
The same release fixes CVE-2026-105482, a NUL byte in a name passed to dns.resolve4 and the other resolver functions that take a name. dns.lookup already rejected that byte on all four binaries, with ERR_INVALID_ARG_VALUE. A test that only calls dns.lookup will not see the remaining hole.
dns.resolve4 was pointed at a UDP listener on 127.0.0.1, so the question did not leave the host. The name argument contained a NUL between nul-probe.invalid and a second label. 22.23.3 and 24.22.0 did not throw. Each sent one query. The captured question name was nul-probe.invalid. The suffix after the NUL was not in the packet. The error string Node printed still contained the original argument, with the NUL in the middle, and the code was ECONNREFUSED because the listener did not answer. A caller that logs that error can believe the full name was queried. The packet did not contain the full name.
22.23.4 and 24.22.1 threw ERR_INVALID_ARG_VALUE from resolve4 before the callback. A listener left up for the 24.22.1 call received no packet and timed out. That is the check. It does not say what a name without a NUL does, and it does not exercise dns.lookup, which was already refusing the byte. The 22.23.4 call raised the same error from resolve4 and did not reach the callback. The empty-packet capture was repeated for 24.22.1, not as a second capture of 22.23.4.
Verify the binary that will run
node -v is enough to separate these four builds. It is not enough to infer the other line. A 22.23.3 process does not have the 24.22.0 DNS-name acceptance. A 24.22.0 process does not have the 22.23.3 IP-SAN match for 127.1. Moving a 22 line to 22.23.4 answers that line. It says nothing about a 24.22.0 binary that is still on the path, and it says nothing about 26.x, which this run did not execute. The October advisory lists 26.12.1 as the fixed current release. Repeat the handshake against that binary if 26.x is what will run.
Read the version from the binary the process will execute.
node -v
node -p process.versions.openssl
Generate the two certificates in an empty directory. They are test material. Remove them when the check is done. The -nodes option leaves the generated key unencrypted, so do not reuse this pattern for a service key.
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out dns127.pem -days 1 -nodes \
-subj "/CN=dns-literal" -addext "subjectAltName=DNS:127.0.0.1"
openssl req -x509 -newkey rsa:2048 -keyout key-ip.pem -out ip127.pem -days 1 -nodes \
-subj "/CN=ip-san" -addext "subjectAltName=IP:127.0.0.1"
The minimum pair is 127.0.0.1 and 127.1, against the DNS-only SAN and against the IP SAN. Connect with host and servername set to the spelling, ca set to the test certificate, and rejectUnauthorized left at its default. Record authorizationError, not only the process status. Both a refused name and a closed port can end the process. The error text is what distinguishes them.
On 24.22.1 and 22.23.4, 127.1 should fail both certificates, with the non-canonical text, and 127.0.0.1 should match only the IP SAN. On 24.22.0, 127.1 should succeed against DNS:127.0.0.1 and fail against the IP SAN. On 22.23.3, 127.1 should fail the DNS SAN and succeed against the IP SAN. Any other pattern means the binary is not one of these four, or the certificate is not the certificate you think it is.
A custom checkServerIdentity replaces this check. If the application supplies one, call tls.checkServerIdentity first and then add only the extra rule. A version upgrade does not repair a callback that never calls the default. That is a separate test from the spelling comparison.
Do not treat this as a test of the other October fixes. The release also updates bundled roots, OpenSSL, c-ares, and the Brotli decoder. None of those were exercised here. A successful 127.1 rejection does not say the Brotli decoder is patched, and a decoder crash is not evidence about checkServerIdentity.
The result on these four binaries is specific. 24.22.0 authorizes 127.1, 0x7f.0.0.1, 2130706433, the padded decimal forms, and the fullwidth forms against a certificate whose only SAN is DNS:127.0.0.1 or DNS:*.0.0.1. 22.23.3 rejects those as IP addresses missing from that certificate, and it authorizes the same spellings when the certificate has IP Address:127.0.0.1. 22.23.4 and 24.22.1 reject the non-canonical spellings in both cases and still authorize canonical 127.0.0.1 against the IP SAN. dns.resolve4 on the two older binaries sent a question for the labels before the NUL. The two newer binaries threw, and the 24.22.1 capture received no packet.