GHSA-8Q49-2H5H-434X

GHSA-8Q49-2H5H-434X is a medium-severity server-side request forgery (SSRF) vulnerability in @frontmcp/adapters (npm), affecting versions <= 1.5.5. It is fixed in 1.5.6.

Does this CVE actually affect you?

Kodem shows which CVEs are reachable and running in your applications, so you fix what's exploitable, not just what's listed.

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Runtime intelligence, not another scanner.

Summary

FrontMCP: Server-Side Request Forgery (SSRF) in the OpenAPI adapter spec-change poller

The OpenAPI adapter's spec-change poller (OpenApiSpecPoller) re-fetched the
configured spec url on a timer using a raw global fetch(), bypassing the SSRF
guard (safeFetch / assertUrlSafe) that OpenAPIToolGenerator.fromURL() applies
to the initial spec load. As a result, the pinning/DNS-resolution hardening delivered
via mcp-from-openapi >= 2.5.0 (advisory GHSA-65h7-9wrw-629c) protected the initial
load but not the recurring poll of the same URL. When polling is enabled against
an untrusted or attacker-influenceable spec URL, this is an unguarded SSRF vector.

Details

The initial spec load is guarded. OpenapiAdapter resolves a secure refResolution
policy and passes it to the guarded loader:

// libs/adapters/src/openapi/openapi.adapter.ts, initializeGenerator()
return await OpenAPIToolGenerator.fromURL(this.options.url, {
  // ...
  followRedirects: this.options.loadOptions?.followRedirects ?? false,
  refResolution, // secure default: external $refs off, internal targets blocked
});

But the poller, which re-fetches the same URL on every interval, did not:

// libs/adapters/src/openapi/openapi-spec-poller.ts, doFetch() (vulnerable, <= 1.5.5)
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), this.fetchTimeoutMs);
try {
  const response = await fetch(this.url, {   // <-- raw global fetch, no SSRF guard
    headers,
    signal: controller.signal,
  });
  // ...hash the body, fire onChanged...
}

Because doFetch() never called safeFetch, none of the guard's protections applied
to the polled request:

  • no allow-list / block-list enforcement (allowedHosts / blockedHosts);
  • no internal/private/loopback/link-local/CGNAT/cloud-metadata IP blocking;
  • no DNS resolution of the hostname (so a DNS name that resolves to an internal IP,
    e.g. http://127.0.0.1.nip.io/, was reached);
  • no connection pinning to the validated IP (DNS-rebinding TOCTOU);
  • no per-hop re-validation of HTTP redirects.

This is the identical threat model to fromURL() / external $ref resolution
(GHSA-65h7-9wrw-629c), applied to a request path that the fix for that advisory did
not cover.

Preconditions

Exploitation requires both:

  1. polling.enabled: true on an OpenapiAdapter (polling is off by default and
    requires the URL-based url option, not an inline spec); and
  2. the spec url is untrusted / attacker-influenceable (e.g. it is derived from user
    input, a tenant-supplied value, or otherwise not a fixed trusted constant), or an
    otherwise-trusted spec host is attacker-controlled or can redirect.

Servers that poll a fixed, trusted, first-party spec URL are not exposed in practice,
though they still benefit from the guard as defense-in-depth.

Proof of concept

import { OpenapiAdapter } from '@frontmcp/adapters';

// url is attacker-influenceable and points (directly, via DNS, or via redirect)
// at an internal target; polling re-fetches it every interval.
const adapter = OpenapiAdapter.init({
  name: 'evil',
  url: 'http://169.254.169.254/latest/meta-data/', // or http://127.0.0.1.nip.io/...
  polling: { enabled: true, intervalMs: 5000 },
});

await adapter.fetch();   // initial load IS guarded (blocked)
adapter.startPolling();  // <= 1.5.5: each poll issues an UNGUARDED GET to the internal target

On <= 1.5.5 the timed poll reaches the internal address. On the patched version the
poll fails closed (no request is made; the failure is logged) exactly as the initial
load does.

Remediation

Upgrade @frontmcp/adapters to 1.5.6 or later. No configuration change is required:
polling now inherits the same secure defaults as the initial spec load (external
targets blocked, redirects not followed). To poll a genuinely internal or localhost
spec server in a trusted environment, opt in explicitly with
loadOptions.refResolution.allowInternalIPs: true, the same knob that gates the
initial load.

Workarounds

For users who cannot upgrade immediately:

  • disable polling (polling.enabled: false) on adapters whose spec url is not a
    fixed, trusted, first-party value; or
  • only enable polling against spec URLs you fully control, served over HTTPS from a
    host that cannot be made to redirect to internal targets; and
  • enforce network egress controls / an allow-list at the platform layer so the server
    cannot reach internal ranges or cloud-metadata endpoints.

Impact

A server that enables spec polling against an untrusted or attacker-influenceable
spec URL will, on every poll interval, issue a server-side GET to whatever host the
URL (or a DNS name it resolves to, or a redirect it returns) points at, including
internal-only addresses unreachable from the public internet. Consequences include:

  • reading cloud-instance metadata endpoints (e.g. 169.254.169.254), credential /
    token theft;
  • probing and reaching internal services and private-range hosts (internal network
    scanning);
  • DNS-rebinding to swap a public host for an internal one between validation and
    connection.

The poller issues GET requests only, so the primary impact is confidentiality
(reaching and reading internal endpoints); the fetched body is content-hashed to
detect change and the subsequent tool rebuild goes back through the guarded
fromURL() path.

Untrusted input controls the target URL of a server-initiated request, which may reach internal services not otherwise accessible from outside. Typical impact: access to internal metadata services, internal APIs, or cloud credentials.

GHSA-8Q49-2H5H-434X has a CVSS score of 5.9 (Medium). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (1.5.6); upgrading removes the vulnerable code path.

Affected versions

@frontmcp/adapters (<= 1.5.5)

Security releases

@frontmcp/adapters → 1.5.6 (npm)

Kodem intelligence

Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.

Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.

Already deployed Kodem?

See it in your environmentNew to Kodem? Get a demo →

Remediation advice

The fix routes the poller through the same SSRF guard as the initial load, with the
same policy, so both paths share one DNS resolution + connection pinning and cannot
diverge:

  • OpenApiSpecPoller.doFetch() now calls safeFetch(this.url, { headers, timeoutMs, followRedirects, ssrf }) from mcp-from-openapi instead of the global fetch().
  • OpenapiAdapter.startPolling() injects the adapter's resolved policy into the
    poller: ssrf: normalizeSsrfOptions(this.resolveRefResolution()) and
    followRedirects: loadOptions?.followRedirects ?? false, identical to what
    fromURL() receives.
  • SpecPollerOptions gained optional ssrf / followRedirects; standalone use of
    OpenApiSpecPoller defaults to the secure policy (internal targets blocked,
    redirects not followed).

Files changed:

  • libs/adapters/src/openapi/openapi-spec-poller.ts
  • libs/adapters/src/openapi/openapi-spec-poller.types.ts
  • libs/adapters/src/openapi/openapi.adapter.ts

Requires mcp-from-openapi >= 2.5.0 (already a dependency at 2.5.1), which exports
safeFetch / normalizeSsrfOptions and performs the resolved-IP validation and
connection pinning.

Frequently Asked Questions

  1. What is GHSA-8Q49-2H5H-434X? GHSA-8Q49-2H5H-434X is a medium-severity server-side request forgery (SSRF) vulnerability in @frontmcp/adapters (npm), affecting versions <= 1.5.5. It is fixed in 1.5.6. Untrusted input controls the target URL of a server-initiated request, which may reach internal services not otherwise accessible from outside.
  2. How severe is GHSA-8Q49-2H5H-434X? GHSA-8Q49-2H5H-434X has a CVSS score of 5.9 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
  3. Which versions of @frontmcp/adapters are affected by GHSA-8Q49-2H5H-434X? @frontmcp/adapters (npm) versions <= 1.5.5 is affected.
  4. Is there a fix for GHSA-8Q49-2H5H-434X? Yes. GHSA-8Q49-2H5H-434X is fixed in 1.5.6. Upgrade to this version or later.
  5. Is GHSA-8Q49-2H5H-434X exploitable, and should I be worried? Whether GHSA-8Q49-2H5H-434X is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
  6. What actually determines whether GHSA-8Q49-2H5H-434X is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
  7. How do I fix GHSA-8Q49-2H5H-434X? Upgrade @frontmcp/adapters to 1.5.6 or later.

Other vulnerabilities in @frontmcp/adapters

Stop the waste.
Protect your environment with Kodem.