Skip to main content
Vulnerability Database/CVE-2026-58485

CVE-2026-58485: mcp-searxng SSRF Vulnerability

CVE-2026-58485 is a server-side request forgery flaw in mcp-searxng that allows attackers to access internal services through DNS rebinding. This post explains its technical details, affected versions, and mitigation.

Published:

CVE-2026-58485 Overview

CVE-2026-58485 is a Server-Side Request Forgery (SSRF) vulnerability in mcp-searxng, a Model Context Protocol (MCP) server that provides AI assistants with web search and URL-reading capabilities through SearXNG. Versions prior to 1.7.1 validate only the literal hostname of caller-supplied URLs before performing HTTP fetches. An attacker-controlled hostname that resolves via DNS to a private, loopback, link-local, or cloud-metadata address bypasses this lexical check. The MCP server then connects to the internal destination and returns the response to the caller. The issue is tracked under [CWE-918] and is fixed in version 1.7.1.

Critical Impact

Unauthenticated network clients in the default HTTP configuration can read internal services, exfiltrate credentials or service tokens, and enumerate reachable internal hosts through the web_url_read tool.

Affected Products

  • mcp-searxng versions prior to 1.7.1
  • Deployments exposing the MCP server over HTTP without MCP_HTTP_ALLOW_PRIVATE_URLS opt-out review
  • STDIO deployments where prompt-influenced tool selection can supply attacker URLs

Discovery Timeline

  • 2026-09-15 - CVE-2026-58485 published to the National Vulnerability Database (NVD)
  • 2026-09-15 - Last updated in NVD database

Technical Details for CVE-2026-58485

Vulnerability Analysis

The web_url_read tool exposed by mcp-searxng accepts a caller-controlled URL through src/index.ts and passes it to assertUrlAllowed() in src/url-reader.ts. That function validates only the literal hostname string. After the lexical check passes, undiciFetch() performs operating-system DNS resolution independently and connects to whatever address is returned.

This design creates a time-of-check to time-of-use (TOCTOU) gap between hostname validation and network connection. A public-looking hostname such as attacker.example.com can be configured with an A record pointing to 169.254.169.254, 127.0.0.1, or an RFC 1918 address. The lexical filter does not detect this, and the fetch reaches the internal target.

In the default HTTP configuration, no authentication is required to invoke the tool. In STDIO deployments, an attacker can influence the AI assistant through prompt injection to select a malicious URL.

Root Cause

The root cause is incomplete SSRF mitigation. Direct private IP literals are blocked, but hostname validation is performed on the string alone without consulting DNS. The fetch layer resolves the hostname a second time and honors the resulting address without any private-range filtering.

Attack Vector

An attacker registers a hostname whose DNS resolves to a private, loopback, link-local, or cloud-metadata address. The attacker then instructs the MCP server, directly over HTTP or indirectly via a prompt-influenced AI client, to fetch a URL using that hostname. The server retrieves content from the internal target and returns it to the caller, exposing cloud metadata (for example, AWS IMDS at 169.254.169.254), internal admin panels, or service tokens.

typescript
// Patch: src/proxy.ts — DNS-aware lookup that rejects private addresses
import * as dns from "node:dns";
import { Agent, ProxyAgent } from "undici";
import { getHttpSecurityConfig } from "./http-security.js";
import { getConnectOptions } from "./tls-config.js";
import { createUrlSecurityPolicyDnsError, isPrivateAddress } from "./url-security.js";

type LookupCallback = (
  err: NodeJS.ErrnoException | null,
  address: string | dns.LookupAddress[],
  family?: number,
) => void;

export function createUrlReaderLookup() {
  return (hostname: string, options: dns.LookupOptions, callback: LookupCallback): void => {
    if (getHttpSecurityConfig().allowPrivateUrls) {
      (dns.lookup as any)(hostname, options, callback);
      return;
    }

    dns.lookup(hostname, { ...options, all: true }, (error, addresses) => {
      if (error) {
        callback(error, options.all ? [] : "");
        return;
      }

      if (addresses.length === 0) {
        const notFound = new Error(`No DNS records found for ${hostname}`) as NodeJS.ErrnoException;
        notFound.code = "ENOTFOUND";
        callback(notFound, options.all ? [] : "");
        return;
      }
      // Remaining logic filters resolved addresses through isPrivateAddress()
    });
  };
}
// Source: https://github.com/ihor-sokoliuk/mcp-searxng/commit/14575eaaa46a21391477d2b68673858ba6b52bd6

Detection Methods for CVE-2026-58485

Indicators of Compromise

  • Outbound DNS queries from the mcp-searxng host that resolve to RFC 1918, loopback (127.0.0.0/8), link-local (169.254.0.0/16), or cloud metadata addresses.
  • HTTP requests originating from the MCP server process directed at 169.254.169.254, metadata.google.internal, or internal service endpoints.
  • Unexpected web_url_read tool invocations referencing unfamiliar external hostnames followed by connections to internal targets.

Detection Strategies

  • Instrument undici fetches with logging that records both the requested hostname and the resolved IP address, then alert when the resolved address falls in a private range.
  • Correlate MCP server access logs with egress firewall logs to identify tool calls that terminate at internal destinations.
  • Review MCP prompt and tool-call telemetry for hostnames that were recently registered or use uncommon TLDs.

Monitoring Recommendations

  • Log every web_url_read invocation including source client, requested URL, resolved IP, and HTTP status.
  • Monitor for access attempts to cloud instance metadata endpoints from any container or host running the MCP server.
  • Track version metadata across MCP server deployments to identify hosts still running versions below 1.7.1.

How to Mitigate CVE-2026-58485

Immediate Actions Required

  • Upgrade mcp-searxng to version 1.7.1 or later on all deployments.
  • Confirm that MCP_HTTP_ALLOW_PRIVATE_URLS is not set unless internal access is an intentional requirement.
  • Restrict network egress from the MCP server so that only external destinations required by SearXNG are reachable.

Patch Information

The fix is delivered in mcp-searxng version 1.7.1. The patch introduces a custom undici DNS lookup handler that resolves the hostname, evaluates each returned address through isPrivateAddress(), and rejects the connection with a security policy error when any address falls in a private range. See the GitHub Security Advisory GHSA-mrvx-jmjw-vggc, the remediation commit, and the v1.7.1 release notes for complete details.

Workarounds

  • Place the MCP server behind an egress proxy configured to block RFC 1918, loopback, link-local, and cloud metadata addresses.
  • Require authentication on the HTTP transport and restrict callers to trusted networks until the upgrade is applied.
  • Disable or gate the web_url_read tool in STDIO deployments where prompt injection from untrusted content is possible.
bash
# Verify installed version and remove the private-URL opt-out if present
npm ls mcp-searxng
npm install mcp-searxng@1.7.1

# Ensure the opt-out environment variable is not set in the deployment
unset MCP_HTTP_ALLOW_PRIVATE_URLS

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.