Skip to content

VNX-441: Unintended proxy: request-chosen URL fetched and relayed to the client

Detects a server-side fetch of a URL taken from the request whose response is relayed back to the caller (Python requests/httpx/urlopen, Node axios/fetch/got/needle/superagent, http-proxy targets), turning the service into an open proxy into its own network.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-441
Severity Medium
SARIF level warning
Kind sast
Languages JavaScript / TypeScript, Python
CWE CWE-441
CAPEC CAPEC-66
ATT&CK T1190
CWSS vector CWSS:1.0/TI:M/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C
Tags confused-deputy open-proxy ssrf cwe-441
Source internal/sast/rules/vnx-441.rego

Overview

VNX-441 maps to CWE-441: Unintended Proxy or Intermediary (‘Confused Deputy’). A handler that fetches whatever URL the caller names and hands the response back lets anyone use the server’s network position: internal admin panels, cloud metadata endpoints and services behind the firewall all become reachable through it.

The rule reports a fetch whose URL argument is a request value (directly, or through a variable assigned from one in the 12 lines above) when the fetched response is returned, rendered, sent, written or piped to the client within the next 15 lines, before the next handler or function starts. It also reports http-proxy’s proxy.web/proxy.ws with a target taken from the request.

Not reported: a constant URL (request values only in params or body), a URL with a fixed host whose path or query alone comes from the request, a fetch whose response is not relayed (plain SSRF is VNX-918 in Python and VNX-NODE-009 in JavaScript), a flow with an allow-list or URL validation between the source and the fetch, comments, strings and test files.

A relayed fetch is the form of server-side request forgery in which the attacker also reads the response, so VNX-918 and VNX-NODE-009 leave these lines to this rule: one request is one finding.

What Gets Flagged

# FLAGGED: the caller picks the URL and gets the body back
target = request.args.get("url")
resp = requests.get(target, timeout=5)
return Response(resp.content, mimetype=resp.headers.get("Content-Type"))
// FLAGGED: response piped straight to the client
const upstream = await axios.get(req.query.url);
res.send(upstream.data);

Remediation

  1. Route to fixed upstreams; let the client choose a key, not a URL.
  2. If arbitrary URLs are a feature, check the resolved host against an allow-list and block private, loopback and link-local addresses.
  3. Do not relay raw upstream responses, headers or error bodies to the caller.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-441
// nosec vnx-441

Or record an ignore rule: vulnetix ignore add --rule vnx-441 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-441.rego, cli/internal/sast/docs/vnx-441.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.