From 5346fd5d2b378c1d3a4b604d698b977d5fab0306 Mon Sep 17 00:00:00 2001 From: Ren Koya Date: Mon, 10 Aug 2026 10:04:24 +0900 Subject: [PATCH] fix: name three more reserved ranges in the MCP endpoint blocklist The connect-time blocklist is not the SSRF boundary -- workerd's global_fetch_strictly_public is -- but it is what tells a user typing a URL into the connect form why their host will not work. Three ranges of the same class as the entries already there were missing: 100.64.0.0/10 carrier-grade NAT fe80::/10 IPv6 link-local, where only fc00::/7 was covered :: the unspecified address, where only ::1 was covered Without them those hosts reach the fetch and fail as an opaque network error instead. --- packages/mcp-shared/__tests__/endpoint.test.ts | 10 +++++++--- packages/mcp-shared/src/endpoint.ts | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/mcp-shared/__tests__/endpoint.test.ts b/packages/mcp-shared/__tests__/endpoint.test.ts index 57a8cd1d..d91d56ba 100644 --- a/packages/mcp-shared/__tests__/endpoint.test.ts +++ b/packages/mcp-shared/__tests__/endpoint.test.ts @@ -27,8 +27,10 @@ describe("validateCustomEndpoint", () => { for (const host of [ "localhost", "app.localhost", "127.0.0.1", "0.0.0.0", "10.1.2.3", "192.168.0.5", "172.16.9.9", "169.254.169.254", "metadata.google.internal", "thing.internal", - // IPv6 loopback and unique-local, which a URL renders bracketed. - "[::1]", "[fd00::1]", "[fc00::1]", + // Carrier-grade NAT, which some networks route to infrastructure of their own. + "100.64.0.1", "100.127.255.254", + // IPv6 loopback, unspecified, unique-local and link-local, which a URL renders bracketed. + "[::1]", "[::]", "[fd00::1]", "[fc00::1]", "[fe80::1]", "[febf::1]", ]) { expect(validateCustomEndpoint(env(), `https://${host}/mcp`).ok, host).toBe(false); } @@ -43,7 +45,9 @@ describe("validateCustomEndpoint", () => { }); it("does not mistake ordinary hosts for encoded addresses", () => { - for (const host of ["mcp.example.com", "8x8.com", "0x.example.com", "mcp.internal.example.com"]) { + for (const host of ["mcp.example.com", "8x8.com", "0x.example.com", "mcp.internal.example.com", + // Addresses outside the ranges above, which must still be accepted. + "100.63.0.1", "100.128.0.1", "[2606:4700::1111]"]) { expect(isBlockedHost(host), host).toBe(false); } }); diff --git a/packages/mcp-shared/src/endpoint.ts b/packages/mcp-shared/src/endpoint.ts index 94b705f7..0b18f005 100644 --- a/packages/mcp-shared/src/endpoint.ts +++ b/packages/mcp-shared/src/endpoint.ts @@ -23,8 +23,11 @@ const BLOCKED_HOST_PATTERNS = [ /^192\.168\./, /^172\.(1[6-9]|2[0-9]|3[01])\./, /^169\.254\./, + /^100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\./, /^\[?::1\]?$/, + /^\[?::\]?$/, /^\[?f[cd][0-9a-f]{2}:/i, + /^\[?fe[89ab][0-9a-f]:/i, /^metadata\./i, /\.internal$/i, ];