Rook
AI red-teamer · 42nights

SSRF reconnaissance via verbose network error leakage in /api/fetch

medium5.8

info-leak · server.js:72-72

Introduced in 15b34d5cc6 by 42nights on 2026-06-03

Summary

The /api/fetch endpoint at server.js:72 attaches an http error handler that returns the raw Node.js error message to the client via `send(res, 502, `fetch error: ${e.message}`)`. Node's socket/DNS error messages embed details such as the resolved IP, port, and low-level error code (e.g. ECONNREFUSED, EHOSTUNREACH, ETIMEDOUT, ENOTFOUND). An attacker can submit arbitrary internal URLs and read these messages to map the internal network instead of receiving a generic, opaque error.

Impact. An unauthenticated attacker can use the endpoint as an oracle to scan and fingerprint the internal network. By varying the `url` parameter and observing the returned error string (open vs refused vs timeout vs DNS-fail vs TLS-fail), they can enumerate live hosts, open ports, hostnames, and IPs reachable from the server — classic SSRF reconnaissance that typically precedes attacks on internal admin panels, metadata services, or databases.

Vulnerable code — server.js

🔴 .on("error", (e) => send(res, 502, `fetch error: ${e.message}`));

Working exploit

curl -s 'http://127.0.0.1:4600/api/fetch?url=http://127.0.0.1:1/'

Exploit transcript

$ curl -s 'http://127.0.0.1:4600/api/fetch?url=http://127.0.0.1:1/'
HTTP 502  Content-Type: text/plain
fetch error: connect ECONNREFUSED 127.0.0.1:1

Confirmed: HTTP 502 body: 'fetch error: connect ECONNREFUSED 127.0.0.1:1'

CVSS v3.1

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N5.8 (medium)

Recommended fix

AI-suggested fix — review before applying (derived from analysis of untrusted repo content):

Return a generic error to the client and log the detail server-side only.

--- a/server.js
+++ b/server.js
@@
-      .on("error", (e) => send(res, 502, `fetch error: ${e.message}`));
+      .on("error", (e) => {
+        console.error("upstream fetch error", { url, code: e.code, message: e.message });
+        send(res, 502, "upstream fetch failed");
+      });

Additionally, enforce an allow-list of hosts/schemes and block RFC1918, loopback, link-local, and metadata IPs before dispatching the request.

Ship the fix

Rook found it and proved it. Hand the finding — with its working exploit as a failing test — to Otis to write the fix PR.