Severity by source
AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
AV:L and PR:L because exploitation requires code execution inside the Deno process; S:C and C:H because the bypass crosses the permission boundary to reach protected denied endpoints.
Primary rating from Vendor (https://github.com/denoland/deno).
CVSS VectorVendor: https://github.com/denoland/deno
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
Lifecycle Timeline
2DescriptionCVE.org
Summary
Deno's network permission model is designed so that --deny-net rules apply to the resolved IP address of a destination, not just the literal string supplied by the caller. That means --deny-net=127.0.0.1 (or --deny-net=127.0.0.0/8) is expected to block any attempt to reach loopback, regardless of how the hostname is spelled.
On affected versions, the Node.js compatibility TCP path checked the permission against the original hostname string before resolution and then did not re-check after resolution. A caller could therefore pass a numeric alias of an IP address (for example the decimal integer 2130706433 or the hex form 0x7f000001, both of which resolve to 127.0.0.1) and reach the denied destination through node:net.connect or node:http.request's { host, port } options form.
The native Deno.connect(), fetch(), and URL-string variants of node:http.request("http://...") were not affected, because they either re-checked permissions after resolution or normalized the hostname through the URL parser before checking.
Proof of concept
Run on Deno 2.7.14, with a local TCP listener on 127.0.0.1:<PORT>:
import net from "node:net";
// --allow-net + --deny-net=127.0.0.0/8
// (or even --deny-net=127.0.0.1:<PORT>)
net.connect({ host: "2130706433", port: PORT }); // CONNECTED ❌
net.connect({ host: "0x7f000001", port: PORT }); // CONNECTED ❌
net.connect({ host: "127.0.0.1", port: PORT }); // denied ✅The same primitive reached the loopback HTTP listener through node:http when the destination was passed as options rather than as a URL string:
import http from "node:http";
// options-form host - bypasses the deny rule on affected versions
http.request({ hostname: "2130706433", port: PORT, path: "/" }).end();
// URL-string form - correctly denied (URL parser normalizes the host)
http.request(`http://2130706433:${PORT}/`).end();The server-side log showed the bypassed requests arriving from 127.0.0.1 with the numeric alias preserved in the Host header.
Impact
A program that intentionally allows broad outbound network access but uses --deny-net to carve out protected destinations, typically loopback, private/internal ranges, or cloud-instance metadata IPs, could be made to reach those denied destinations from less-trusted code (a dependency, plugin, or attacker-controlled input) that funnels through node:net.connect({ host }) or node:http.request({ hostname }).
The CVSS vector reflects this as a local-attack-vector, permissions-required confidentiality impact: the attacker needs to be able to run code inside the Deno process, and the demonstrated primitive is "reach an explicitly denied IP." It does not by itself exfiltrate data or execute code; the further impact depends on what the now-reachable endpoint exposes.
The confirmed scope is IPv4 numeric hostname aliases reaching a denied resolved IP through the Node TCPWrap / options-host path. URL strings, node:http2, undici, and IPv6 numeric/mapped-address variants were not exhaustively tested by the reporter.
Not affected
- Programs that do not use
--deny-netat all (the bug is specifically about deny rules being bypassed; allow rules were always checked against the original string). - Native Deno networking APIs (
Deno.connect,Deno.connectTls,fetch, ...), these already re-checked permissions after resolution as of PR #33203. - URL-string callers such as
fetch("http://2130706433/")ornode:http.request("http://2130706433/"), the URL parser normalized the hostname to its dotted-quad form before the permission check ran. - Calls that do not provide
host/hostname(e.g. connecting by IP literal or by a name that the deny rule already matches verbatim).
Workarounds
If you cannot upgrade immediately, reduce exposure by:
- Preferring an
--allow-netallowlist over a--deny-netdenylist. An allowlist denies numeric aliases by default because they don't match the listed hostnames; only the destinations you've explicitly permitted can be reached. - Validating untrusted host input before passing it to
node:net.connect/node:http.request. Reject hostnames that are purely decimal integers (/^\d+$/) or begin with0x, as these are the alias forms exploited by the bypass. - Avoiding the Node options-host path for sensitive calls in favour of URL-string forms, which are normalized by the URL parser before the permission check.
AnalysisAI
Deno's Node.js compatibility TCP path (node:net.connect / node:http.request options form) fails to re-check network permissions against the resolved IP address, allowing numeric IPv4 aliases (e.g., decimal integer '2130706433' or hex '0x7f000001' for 127.0.0.1) to bypass --deny-net rules in Deno versions up to and including 2.7.14. Any code executing inside the Deno process - including supply-chain-compromised dependencies or attacker-controlled input - can reach explicitly denied destinations such as loopback services, private ranges, or cloud instance metadata endpoints by exploiting this pre-resolution-only permission check. No public exploit identified at time of analysis via CISA KEV, but publicly available exploit code exists (proof-of-concept published in GHSA-v8fw-85r8-5m23); fix is available in Deno 2.8.0.
Technical ContextAI
Deno's permission model is designed to evaluate --deny-net rules against the resolved IP address of a connection target, not just the caller-supplied string. The affected code path is the Node.js compatibility layer's TCPWrap implementation (pkg:rust/deno), which backs node:net.connect({ host, port }) and node:http.request({ hostname, port }) in options-object form. The root cause is CWE-284 (Improper Access Control): TCPWrap performs its permission check against the pre-resolution hostname string and does not repeat the check after the OS resolves the alias to its canonical IP. IPv4 numeric aliases - both 32-bit decimal integers and hexadecimal representations - are accepted by the underlying OS network stack as valid IP references but do not textually match deny-rule strings like '127.0.0.1' or '127.0.0.0/8'. Native Deno APIs (Deno.connect, Deno.connectTls, fetch) and URL-string-form node:http.request calls are not affected because they either re-check permissions post-resolution or pass the host through the WHATWG URL parser, which normalizes numeric aliases to dotted-quad form before the permission check runs.
RemediationAI
Vendor-released patch: Deno 2.8.0. Upgrade to Deno 2.8.0 or later, which fixes the Node TCPWrap path to re-check permissions against the resolved IP address (see https://github.com/denoland/deno/security/advisories/GHSA-v8fw-85r8-5m23). If an immediate upgrade is not possible, three workarounds reduce exposure with different trade-offs: (1) Replace --deny-net denylists with --allow-net allowlists - allowlists deny numeric aliases by default because they won't match listed hostnames, though this is a potentially disruptive model change that may require enumerating all intended outbound destinations; (2) Validate untrusted host/hostname input before passing it to node:net.connect or node:http.request by rejecting strings matching /^\d+$/ (decimal integer aliases) or strings beginning with '0x' (hexadecimal aliases) - this is targeted but requires identifying every call site that accepts external input; (3) Prefer URL-string call forms (e.g., node:http.request('http://...')) over options-object forms for any connection whose destination may be influenced by untrusted input, since the URL parser normalizes hostnames before the permission check runs.
FortiOS and FortiProxy contain an authentication bypass via the Node.js websocket module allowing unauthenticated remote
Eval injection vulnerability in the internals.batch function in lib/batch.js in the bassmaster plugin before 1.5.2 for t
Flowise version 3.0.5 contains a remote code execution vulnerability in the CustomMCP node. The mcpServerConfig paramete
Node.js 8.5.0 before 8.6.0 allows remote attackers to access unintended files, because a change to ".." handling was inc
An issue was discovered in the node-serialize package 0.0.4 for Node.js. Rated critical severity (CVSS 9.8), this vulner
Directory traversal vulnerability in the st module before 0.2.5 for Node.js allows remote attackers to read arbitrary fi
Multiple SQL injection vulnerabilities in the Manage Accounts page in the AccountManagement.asmx service in the Solarwin
The JS-YAML module before 2.0.5 for Node.js parses input without properly considering the unsafe !!js/function tag, whic
Directory traversal vulnerability in lib/app/index.js in Geddy before 13.0.8 for Node.js allows remote attackers to read
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Eval injection vulnerability in index.js in the syntax-error package before 1.1.1 for Node.js 0.10.x, as used in IBM Rat
The HTTP server in Node.js 0.10.x before 0.10.21 and 0.8.x before 0.8.26 allows remote attackers to cause a denial of se
Same weakness CWE-284 – Improper Access Control
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-38544
GHSA-v8fw-85r8-5m23