@bluefields/primitives 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ssrf.js ADDED
@@ -0,0 +1,432 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * SSRF-safe URL validation and HTTP client (Reviews #6, #7, #10).
4
+ *
5
+ * Every URL that crosses a trust boundary into our platform — customer
6
+ * webhook URLs, customer watch URLs, MCP scrape_url arguments — must pass
7
+ * through `validateUrlForExternalRequest` before we make any outbound
8
+ * request. The validator is the first line of defense; `createSsrfSafeHttpClient`
9
+ * is the second, catching DNS rebinding by re-validating at connect time.
10
+ *
11
+ * This module is reused widely. Two rules to keep in mind when extending it:
12
+ * 1. Default-deny. Add new categories to the deny side; don't allowlist exceptions.
13
+ * 2. Validate, don't sanitize. We reject bad URLs; we never massage them into
14
+ * "fixed" URLs and proceed.
15
+ */
16
+ import { lookup as dnsLookup } from 'node:dns/promises';
17
+ import { isIPv4, isIPv6 } from 'node:net';
18
+ import { Agent, ProxyAgent, fetch as undiciFetch } from 'undici';
19
+ export class SsrfValidationError extends Error {
20
+ reason;
21
+ constructor(message, reason) {
22
+ super(message);
23
+ this.name = 'SsrfValidationError';
24
+ this.reason = reason;
25
+ }
26
+ }
27
+ // Hostnames that are known metadata services — reject before DNS even runs.
28
+ const METADATA_HOSTNAMES = new Set([
29
+ 'metadata.google.internal',
30
+ 'metadata.goog',
31
+ 'metadata',
32
+ ]);
33
+ // Internal-only domains the platform owns — reject before DNS.
34
+ // Matches both the bare domain and any subdomain.
35
+ const INTERNAL_DOMAIN_SUFFIXES = ['bluefields.dev', 'internal.bluefields.dev'];
36
+ const HTTPS_PROTOCOL = 'https:';
37
+ /**
38
+ * Validate that `url` is safe to use for an outbound HTTPS request.
39
+ *
40
+ * Throws `SsrfValidationError` on any rejection. Callers should treat the
41
+ * error as a 4xx validation failure (not a 5xx server error).
42
+ */
43
+ export async function validateUrlForExternalRequest(url) {
44
+ let parsed;
45
+ try {
46
+ parsed = new URL(url);
47
+ }
48
+ catch {
49
+ throw new SsrfValidationError(`URL did not parse: ${url}`, 'invalid_url');
50
+ }
51
+ if (parsed.protocol !== HTTPS_PROTOCOL) {
52
+ throw new SsrfValidationError(`unsupported protocol: ${parsed.protocol} (only https is allowed)`, 'unsupported_protocol');
53
+ }
54
+ // WHATWG URL returns IPv6 hostnames in bracketed form (`[::1]`); strip
55
+ // brackets so `isIPv6` and the IP-range predicates see the bare literal.
56
+ // Also lowercase defensively even though the parser already normalizes it.
57
+ const hostname = parsed.hostname.toLowerCase().replace(/^\[|\]$/g, '');
58
+ if (METADATA_HOSTNAMES.has(hostname)) {
59
+ throw new SsrfValidationError(`metadata endpoint blocked: ${hostname}`, 'metadata_endpoint');
60
+ }
61
+ for (const suffix of INTERNAL_DOMAIN_SUFFIXES) {
62
+ if (hostname === suffix || hostname.endsWith(`.${suffix}`)) {
63
+ throw new SsrfValidationError(`internal domain blocked: ${hostname}`, 'internal_domain');
64
+ }
65
+ }
66
+ // If the URL is an IP literal (brackets already stripped above), validate
67
+ // it directly without DNS.
68
+ if (isIPv4(hostname) || isIPv6(hostname)) {
69
+ if (isPrivateOrReservedIp(hostname)) {
70
+ throw new SsrfValidationError(`private/reserved IP blocked: ${hostname}`, 'private_ip');
71
+ }
72
+ return;
73
+ }
74
+ // Resolve via DNS. `all: true` surfaces every record so we can catch the
75
+ // multi-A-record attack where one address is public and another is private.
76
+ // The `as const` is required for TS to pick the LookupAllOptions overload.
77
+ let addresses;
78
+ try {
79
+ addresses = await dnsLookup(hostname, { all: true, verbatim: true });
80
+ }
81
+ catch (err) {
82
+ throw new SsrfValidationError(`DNS lookup failed for ${hostname}: ${err.message}`, 'dns_failure');
83
+ }
84
+ for (const addr of addresses) {
85
+ if (isPrivateOrReservedIp(addr.address)) {
86
+ throw new SsrfValidationError(`${hostname} resolves to private/reserved IP ${addr.address}`, 'private_ip');
87
+ }
88
+ }
89
+ }
90
+ /**
91
+ * Returns true if `ip` is in any private, reserved, loopback, link-local,
92
+ * multicast, broadcast, documentation, or AWS-metadata range — anything we
93
+ * don't want our platform's egress to reach. Exported so tests can verify
94
+ * each category and other callers (e.g. attestation manifest integrity
95
+ * checks on `proxy_egress_ip`) can reuse the same predicate.
96
+ */
97
+ export function isPrivateOrReservedIp(ip) {
98
+ if (isIPv4(ip))
99
+ return isIPv4PrivateOrReserved(ip);
100
+ if (isIPv6(ip))
101
+ return isIPv6PrivateOrReserved(ip);
102
+ // Unrecognized format — fail closed.
103
+ return true;
104
+ }
105
+ function ipv4ToUint32(ip) {
106
+ const parts = ip.split('.');
107
+ if (parts.length !== 4)
108
+ return Number.NaN;
109
+ let n = 0;
110
+ for (const p of parts) {
111
+ if (!/^\d{1,3}$/.test(p))
112
+ return Number.NaN;
113
+ const v = Number(p);
114
+ if (v < 0 || v > 255)
115
+ return Number.NaN;
116
+ n = (n << 8) | v;
117
+ }
118
+ return n >>> 0;
119
+ }
120
+ function isIPv4PrivateOrReserved(ip) {
121
+ const n = ipv4ToUint32(ip);
122
+ if (!Number.isFinite(n))
123
+ return true;
124
+ // 0.0.0.0/8 — "this network" / unspecified
125
+ if (n <= 0x00ffffff)
126
+ return true;
127
+ // 10.0.0.0/8
128
+ if (n >= 0x0a000000 && n <= 0x0affffff)
129
+ return true;
130
+ // 100.64.0.0/10 — Carrier-grade NAT (RFC 6598)
131
+ if (n >= 0x64400000 && n <= 0x647fffff)
132
+ return true;
133
+ // 127.0.0.0/8 — loopback
134
+ if (n >= 0x7f000000 && n <= 0x7fffffff)
135
+ return true;
136
+ // 169.254.0.0/16 — link-local (includes 169.254.169.254 metadata)
137
+ if (n >= 0xa9fe0000 && n <= 0xa9feffff)
138
+ return true;
139
+ // 172.16.0.0/12
140
+ if (n >= 0xac100000 && n <= 0xac1fffff)
141
+ return true;
142
+ // 192.0.0.0/24 — IETF Protocol Assignments
143
+ if (n >= 0xc0000000 && n <= 0xc00000ff)
144
+ return true;
145
+ // 192.0.2.0/24 — TEST-NET-1
146
+ if (n >= 0xc0000200 && n <= 0xc00002ff)
147
+ return true;
148
+ // 192.168.0.0/16
149
+ if (n >= 0xc0a80000 && n <= 0xc0a8ffff)
150
+ return true;
151
+ // 198.18.0.0/15 — benchmarking
152
+ if (n >= 0xc6120000 && n <= 0xc613ffff)
153
+ return true;
154
+ // 198.51.100.0/24 — TEST-NET-2
155
+ if (n >= 0xc6336400 && n <= 0xc63364ff)
156
+ return true;
157
+ // 203.0.113.0/24 — TEST-NET-3
158
+ if (n >= 0xcb007100 && n <= 0xcb0071ff)
159
+ return true;
160
+ // 224.0.0.0/4 — multicast
161
+ if (n >= 0xe0000000 && n <= 0xefffffff)
162
+ return true;
163
+ // 240.0.0.0/4 — reserved (includes 255.255.255.255 broadcast)
164
+ if (n >= 0xf0000000)
165
+ return true;
166
+ return false;
167
+ }
168
+ /**
169
+ * Expand any valid IPv6 textual representation (including shorthand and
170
+ * IPv4-mapped forms) into a 16-byte buffer. Returns null on malformed input.
171
+ *
172
+ * Implemented inline rather than via a library because the policy "default
173
+ * deny on parse failure" is integral to the SSRF defense — a bug in a
174
+ * permissive parser would silently allow attacker-controlled inputs.
175
+ */
176
+ function expandIPv6(ip) {
177
+ let cleaned = ip.toLowerCase();
178
+ // Strip surrounding brackets if present.
179
+ if (cleaned.startsWith('[') && cleaned.endsWith(']')) {
180
+ cleaned = cleaned.slice(1, -1);
181
+ }
182
+ // Strip zone identifier (% suffix) — link-local sometimes carries it.
183
+ const zoneIdx = cleaned.indexOf('%');
184
+ if (zoneIdx !== -1)
185
+ cleaned = cleaned.slice(0, zoneIdx);
186
+ // Detect IPv4 tail (e.g. ::ffff:192.0.2.1 or ::192.0.2.1).
187
+ const lastColon = cleaned.lastIndexOf(':');
188
+ const tail = lastColon === -1 ? '' : cleaned.slice(lastColon + 1);
189
+ let head = cleaned;
190
+ let v4Bytes = null;
191
+ if (tail.includes('.')) {
192
+ if (!isIPv4(tail))
193
+ return null;
194
+ const v4 = ipv4ToUint32(tail);
195
+ if (!Number.isFinite(v4))
196
+ return null;
197
+ v4Bytes = [(v4 >>> 24) & 0xff, (v4 >>> 16) & 0xff, (v4 >>> 8) & 0xff, v4 & 0xff];
198
+ head = cleaned.slice(0, lastColon);
199
+ }
200
+ // Split on the at-most-one "::" run.
201
+ const parts = head.split('::');
202
+ if (parts.length > 2)
203
+ return null;
204
+ const left = parts[0] ? parts[0].split(':') : [];
205
+ const right = parts.length === 2 && parts[1] ? parts[1].split(':') : [];
206
+ const wantWords = v4Bytes ? 6 : 8;
207
+ let words;
208
+ if (parts.length === 1) {
209
+ if (left.length !== wantWords)
210
+ return null;
211
+ words = left;
212
+ }
213
+ else {
214
+ const missing = wantWords - left.length - right.length;
215
+ if (missing < 0)
216
+ return null;
217
+ words = [...left, ...new Array(missing).fill('0'), ...right];
218
+ }
219
+ const out = new Uint8Array(16);
220
+ for (let i = 0; i < words.length; i++) {
221
+ const w = words[i];
222
+ if (!/^[0-9a-f]{1,4}$/.test(w))
223
+ return null;
224
+ const v = Number.parseInt(w, 16);
225
+ if (!Number.isInteger(v) || v < 0 || v > 0xffff)
226
+ return null;
227
+ out[i * 2] = (v >>> 8) & 0xff;
228
+ out[i * 2 + 1] = v & 0xff;
229
+ }
230
+ if (v4Bytes) {
231
+ out[12] = v4Bytes[0];
232
+ out[13] = v4Bytes[1];
233
+ out[14] = v4Bytes[2];
234
+ out[15] = v4Bytes[3];
235
+ }
236
+ return out;
237
+ }
238
+ function isIPv6PrivateOrReserved(ip) {
239
+ const b = expandIPv6(ip);
240
+ if (!b)
241
+ return true;
242
+ // :: — unspecified
243
+ let allZero = true;
244
+ for (let i = 0; i < 16; i++) {
245
+ if (b[i] !== 0) {
246
+ allZero = false;
247
+ break;
248
+ }
249
+ }
250
+ if (allZero)
251
+ return true;
252
+ // ::1 — loopback
253
+ let loopback = true;
254
+ for (let i = 0; i < 15; i++) {
255
+ if (b[i] !== 0) {
256
+ loopback = false;
257
+ break;
258
+ }
259
+ }
260
+ if (loopback && b[15] === 1)
261
+ return true;
262
+ // ::ffff:0:0/96 — IPv4-mapped. Bytes 0-9 = 0, bytes 10-11 = 0xff. Tail
263
+ // is an IPv4 address; defer to the IPv4 predicate so we catch e.g.
264
+ // ::ffff:127.0.0.1 as loopback.
265
+ let mappedPrefix = true;
266
+ for (let i = 0; i < 10; i++) {
267
+ if (b[i] !== 0) {
268
+ mappedPrefix = false;
269
+ break;
270
+ }
271
+ }
272
+ if (mappedPrefix && b[10] === 0xff && b[11] === 0xff) {
273
+ const v4 = `${b[12]}.${b[13]}.${b[14]}.${b[15]}`;
274
+ return isIPv4PrivateOrReserved(v4);
275
+ }
276
+ // 64:ff9b::/96 — IPv4/IPv6 translation (RFC 6052)
277
+ if (b[0] === 0x00 && b[1] === 0x64 && b[2] === 0xff && b[3] === 0x9b) {
278
+ let zerosOk = true;
279
+ for (let i = 4; i < 12; i++) {
280
+ if (b[i] !== 0) {
281
+ zerosOk = false;
282
+ break;
283
+ }
284
+ }
285
+ if (zerosOk) {
286
+ const v4 = `${b[12]}.${b[13]}.${b[14]}.${b[15]}`;
287
+ return isIPv4PrivateOrReserved(v4);
288
+ }
289
+ }
290
+ // 100::/64 — discard-only address block (RFC 6666)
291
+ if (b[0] === 0x01 && b[1] === 0x00 && b[2] === 0 && b[3] === 0) {
292
+ let zerosOk = true;
293
+ for (let i = 4; i < 8; i++) {
294
+ if (b[i] !== 0) {
295
+ zerosOk = false;
296
+ break;
297
+ }
298
+ }
299
+ if (zerosOk)
300
+ return true;
301
+ }
302
+ // 2001:db8::/32 — documentation
303
+ if (b[0] === 0x20 && b[1] === 0x01 && b[2] === 0x0d && b[3] === 0xb8)
304
+ return true;
305
+ // fc00::/7 — Unique Local Addresses (covers fd00:ec2::/64 AWS IPv6 metadata)
306
+ if ((b[0] & 0xfe) === 0xfc)
307
+ return true;
308
+ // fe80::/10 — link-local
309
+ if (b[0] === 0xfe && (b[1] & 0xc0) === 0x80)
310
+ return true;
311
+ // ff00::/8 — multicast
312
+ if (b[0] === 0xff)
313
+ return true;
314
+ return false;
315
+ }
316
+ /**
317
+ * Undici lookup callback that re-validates each candidate address at
318
+ * connect time. Exported for testability; created via
319
+ * `createSsrfSafeHttpClient` for production use.
320
+ *
321
+ * The signature matches Node's `dns.lookup` callback so undici can call it
322
+ * as its `connect.lookup`. We always do an `all: true` lookup internally so
323
+ * a multi-record DNS response can't slip a private IP past us by chance of
324
+ * record ordering — we only return a public one.
325
+ */
326
+ export function ssrfSafeLookup(hostname, options, callback) {
327
+ // undici (and node:net.connect) may pass family as a number (0/4/6) or
328
+ // as the strings 'IPv4'/'IPv6'. Normalize to a number for dns.lookup.
329
+ let family = 0;
330
+ if (typeof options.family === 'number')
331
+ family = options.family;
332
+ else if (options.family === 'IPv4')
333
+ family = 4;
334
+ else if (options.family === 'IPv6')
335
+ family = 6;
336
+ dnsLookup(hostname, { all: true, family, verbatim: true }).then((addresses) => {
337
+ // Defend against malformed dns.lookup results that contain entries
338
+ // with no address (observed in some Node + Alpine combinations on
339
+ // hosts that have both IPv4 + IPv6 A records but one record family
340
+ // returns partial data). Drop those before checking private-IP-ness
341
+ // so we don't hand undici an `undefined` host.
342
+ const publicOnes = addresses.filter((a) => typeof a.address === 'string' &&
343
+ a.address.length > 0 &&
344
+ !isPrivateOrReservedIp(a.address));
345
+ if (publicOnes.length === 0) {
346
+ callback(new SsrfValidationError(`${hostname} has no public IP addresses at connect time`, 'private_ip'), '', 0);
347
+ return;
348
+ }
349
+ // undici 6.x calls this lookup with options.all === true,
350
+ // expecting callback(err, Array<{address, family}>). Node's net
351
+ // module uses the legacy options.all === false form,
352
+ // callback(err, address, family). Honor both.
353
+ const wantAll = options.all === true;
354
+ if (wantAll) {
355
+ // biome-ignore lint/suspicious/noExplicitAny: array-form callback overload
356
+ callback(null, publicOnes);
357
+ }
358
+ else {
359
+ const first = publicOnes[0];
360
+ callback(null, first.address, first.family);
361
+ }
362
+ }, (err) => callback(err, '', 0));
363
+ }
364
+ /**
365
+ * Diagnostic helper — fetch a URL through an arbitrary HTTP proxy.
366
+ * Used by the /debug/diagnostics/proxy-test endpoint to verify
367
+ * provider reachability from inside the api container without going
368
+ * through Patchright/Chromium. Not for production traffic; the
369
+ * standard fetcher path uses ssrfSafeFetch.
370
+ *
371
+ * The target `url` is SSRF-validated up front (it can't go through the
372
+ * connect-time `ssrfSafeLookup`, since the dispatcher connects to the proxy,
373
+ * not the target). The proxy itself is operator-supplied via the admin-gated
374
+ * diagnostic, so it isn't validated here.
375
+ */
376
+ export async function proxyFetch(url, proxy, timeoutMs = 15_000) {
377
+ // Defense-in-depth: reject a private/metadata/internal target before we
378
+ // route it through the proxy (the connect-time lookup can't see it here).
379
+ await validateUrlForExternalRequest(url);
380
+ // Embed user:pass directly in the proxy URL — undici's ProxyAgent
381
+ // expects this style; the `token` option is for bearer-style tokens,
382
+ // not Basic auth.
383
+ const u = new URL(proxy.server);
384
+ u.username = encodeURIComponent(proxy.username);
385
+ u.password = encodeURIComponent(proxy.password);
386
+ const agent = new ProxyAgent({
387
+ uri: u.toString(),
388
+ connectTimeout: timeoutMs,
389
+ bodyTimeout: timeoutMs,
390
+ headersTimeout: timeoutMs,
391
+ });
392
+ // biome-ignore lint/suspicious/noExplicitAny: undici dispatcher extension
393
+ return undiciFetch(url, { dispatcher: agent });
394
+ }
395
+ /**
396
+ * SSRF-safe fetch helper — uses undici's fetch (not Node's global fetch)
397
+ * because Node's global fetch silently ignores the `dispatcher` field
398
+ * on RequestInit. Re-uses one dispatcher per process for efficiency.
399
+ *
400
+ * Callers that just want "fetch this URL, refuse if it resolves to a
401
+ * private IP" should use this instead of constructing the dispatcher
402
+ * themselves.
403
+ */
404
+ let sharedSsrfDispatcher = null;
405
+ export async function ssrfSafeFetch(url, init) {
406
+ if (!sharedSsrfDispatcher)
407
+ sharedSsrfDispatcher = createSsrfSafeHttpClient();
408
+ // biome-ignore lint/suspicious/noExplicitAny: undici extension
409
+ return undiciFetch(url, {
410
+ ...init,
411
+ dispatcher: sharedSsrfDispatcher,
412
+ });
413
+ }
414
+ /**
415
+ * Build an undici Agent that pins each connection to a public IP and
416
+ * times out at 10s. Use this dispatcher wherever the platform makes an
417
+ * outbound request on behalf of a customer (webhook delivery, fetcher
418
+ * Tier 0, MCP scrape_url backend).
419
+ *
420
+ * Redirects: undici re-runs the dispatcher (and thus our lookup) for each
421
+ * new host encountered, so a redirect to a private IP is rejected at
422
+ * connect time the same way the original URL would be. Callers should
423
+ * still pass `maxRedirections` explicitly per-request — the default is 0.
424
+ */
425
+ export function createSsrfSafeHttpClient() {
426
+ return new Agent({
427
+ headersTimeout: 10_000,
428
+ bodyTimeout: 10_000,
429
+ connect: { lookup: ssrfSafeLookup },
430
+ });
431
+ }
432
+ //# sourceMappingURL=ssrf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssrf.js","sourceRoot":"","sources":["../src/ssrf.ts"],"names":[],"mappings":"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"}