Penligent Başlık

Node.js TLS Bypass: CVE-2026-106069 and CVE-2026-105483

CVE-2026-106069 and CVE-2026-105483 concern how Node.js verifies a TLS peer when a host can be interpreted as an IP address in more than one way. The assessment question is whether connection routing and certificate identity checks agree on the destination. Updating the runtime is the primary response; changing certificate policy to accept more names moves in the wrong direction.

Bu October 21, 2026 Node.js security advisory rates both issues high and lists different affected release lines, summarized below. Keep the inventory specific to each issue.

Two normalization failures at the same trust boundary

IssueAdvisory mechanismAffected lines
CVE-2026-106069A leading-zero IPv4 form can be interpreted differently by WHATWG URL normalization and the operating-system resolver.26.x, 24.x, 22.x
CVE-2026-105483A host containing fullwidth digits can normalize to IPv4 while certificate matching treats it as a DNS name.26.x, 24.x

İçin CVE-2026-106069, the advisory uses 0127.0.0.1: URL rules yield 87.0.0.1, while some operating-system resolvers can interpret it as 127.0.0.1. For CVE-2026-105483, a fullwidth form such as 127.0.0.1 can reach IP-oriented behavior while matching a numeric DNS certificate identity. The resulting risk is acceptance of an identity that does not correctly authenticate the connected IP endpoint.

These mechanisms do not mean an attacker can impersonate every HTTPS site. Applicability depends on the application’s input path, runtime, platform behavior, and certificate conditions. Review services that accept or transform destination host input, especially outbound clients and proxy-like workflows, then establish the prerequisites in the actual deployment. This is a defensive assessment recommendation, not a claim of observed exploitation.

Conceptual Node.js TLS identity model comparing URL normalization and operating-system resolution with the connected address.
Conceptual model of the advisory trust boundary; this is not a complete Node.js internal call graph.

Patch the runtime that actually makes the connection

The release notes identify these October 21 security releases: 26.12.1, 24.22.1ve 22.23.4. The 22.x release addresses the applicable non-canonical-IP issue; its scope should not be expanded to claim that 22.x was affected by the fullwidth-digit regression. These are the dated fixed releases discussed here, not a claim that they will remain the newest available versions.

Runtime lineDated security releaseCVE coverage relevant here
26.x26.12.1CVE-2026-106069 and CVE-2026-105483
24.x24.22.1CVE-2026-106069 and CVE-2026-105483
22.x22.23.4CVE-2026-106069

Inventory container images, worker pools, scheduled jobs, sidecar services, and bundled runtimes. Updating a developer laptop does not update a deployed image. After rebuilding and rolling out the selected supported fixed release, inspect the version in the running service and restart or replace old processes. Preserve the image digest or deployment revision with the verification record.

node --version
node -p "JSON.stringify({node:process.version,execPath:process.execPath})"

The second command reports the executable used by that invocation. It does not discover other processes or prove that a separate service uses the same binary. Run the equivalent check within the actual deployment context and compare it with the process or image inventory.

Understand what the certificate identity function proves

Bu Node.js TLS API documentation describes tls.checkServerIdentity() as verifying whether a certificate was issued to a host name or IP address. In the normal connection path, Node calls this check after other certificate checks, including trust checks. Replacing it with a permissive callback changes that security boundary; disabling certificate rejection is not a repair for a hostname-verification defect.

A unit-level identity test is useful because it isolates one decision. It cannot establish that a certificate chains to a trusted authority, that a socket reached the intended address, or that a production application actually uses the default verifier. Preserve those as separate test obligations. This separation prevents a small regression check from being presented as a complete TLS assessment.

A safe regression check with no network traffic

The following example uses synthetic certificate objects and makes no socket connections, DNS lookups, or TLS handshakes. Save it as identity-controls.cjs and run node identity-controls.cjs on a fixed runtime. It compares canonical IPv4 with two unusual host representations and three certificate identity cases. Do not use its synthetic objects as production trust material.

// Synthetic certificate objects; no sockets, DNS resolution, or TLS handshake.
const tls = require('node:tls');
const net = require('node:net');
const assert = require('node:assert/strict');

const certificates = {
  matchingIP: {
    subject: { CN: 'lab.invalid' },
    subjectaltname: 'IP Address:127.0.0.1'
  },
  numericDNS: {
    subject: { CN: 'lab.invalid' },
    subjectaltname: 'DNS:127.0.0.1'
  },
  differentIP: {
    subject: { CN: 'lab.invalid' },
    subjectaltname: 'IP Address:87.0.0.1'
  }
};

for (const host of ['127.0.0.1', '0127.0.0.1', '127.0.0.1']) {
  const results = {};
  for (const [name, cert] of Object.entries(certificates)) {
    try {
      const error = tls.checkServerIdentity(host, cert);
      results[name] = error ? error.code : 'accepted';
    } catch (error) {
      results[name] = error.code || error.name;
    }
  }
  console.log(JSON.stringify({
    node: process.version,
    host,
    literalFamily: net.isIP(host),
    urlHostname: new URL(`https://${host}/`).hostname,
    results
  }));
  for (const [name, result] of Object.entries(results)) {
    const positive = host === '127.0.0.1' && name === 'matchingIP';
    assert.equal(result, positive ? 'accepted' : 'ERR_TLS_CERT_ALTNAME_INVALID');
  }
}

The example was executed on Node.js v24.22.1 in the authoring environment. All nine assertions passed: only canonical 127.0.0.1 with the matching IP SAN was accepted. The numeric DNS SAN and different IP SAN were rejected, as were both non-canonical host forms in this identity-function test. These are observed unit-level results on a patched runtime, not a reproduction of exploitation on a vulnerable release.

Host inputObserved URL hostnameObserved literal familyIdentity-test result on v24.22.1
127.0.0.1127.0.0.14Only the matching IP SAN is accepted
0127.0.0.187.0.0.10All three certificate objects rejected
127.0.0.1127.0.0.10All three certificate objects rejected

Bu net.isIP documentation defines its return value as an IP-family classification or zero for an invalid literal. The URL hostname API represents the hostname produced by URL parsing. Neither value records a real connection destination. The table demonstrates why you should not substitute one parser’s output for another component’s behavior without checking the full data flow.

Verify the deployed path and keep negative controls

In a controlled staging environment, add end-to-end cases for the application’s actual destination input, resolver, connection library, and certificate configuration. Include a legitimate canonical endpoint as a positive control, a mismatched identity as a negative control, and the unusual inputs your policy intends to reject. Observe both the application outcome and the connected address. Do not send test credentials to an untrusted endpoint to gather this evidence.

If a custom checkServerIdentity callback exists, review its return behavior and whether it retains the default verification. Check the client configuration for certificate-validation overrides. A patched runtime cannot compensate for application logic that intentionally accepts any certificate. A negative test that succeeds because validation was disabled identifies a separate configuration or code defect.

Node.js remediation workflow from runtime inventory through deployment, workload restart, function checks and end-to-end controls.
Function-level certificate-object checks and deployed TLS verification are separate test obligations.

Reduce parsing ambiguity without inventing a universal validator

For applications that only need a small destination set, define an explicit input contract and use canonical forms consistently through validation and connection. Reject unsupported host representations before opening a socket. When both domain names and IP literals are valid inputs, test them as distinct cases rather than applying a broad string substitution to everything that looks numeric.

That recommendation is not a complete SSRF defense. DNS changes, redirects, proxies, allowed address ranges, and connection reuse may introduce additional decisions. Review them in the application’s own architecture. Do not claim that a successful net.isIP() call alone establishes an authorized destination or correct TLS identity.

An automated workflow such as Penligent should be evaluated against the same boundaries: runtime inventory, reproducible controls, application-level behavior, and evidence that the actual connection and certificate identity agree. The acceptance case should distinguish a function-level rejection from a verified deployed fix.

Node.js TLS bypass FAQ

Do the two CVEs have identical scope? No. Use the issue-specific affected-line and fixed-release tables above when assigning status to a deployment.

Does the sample prove that a production service is fixed? No. It tests the identity function with synthetic objects on the runtime that executes it. Deployment inventory, application configuration, and end-to-end controls are still required.

Can certificate verification be disabled temporarily as a mitigation? Disabling the trust boundary removes protection instead of repairing the mismatch. Deploy a supported fixed runtime and preserve strict verification while reviewing the application’s input handling.

Gönderiyi paylaş:
İlgili Yazılar
tr_TRTurkish