CVE-2026-54689
mcp-searxng hardened-mode SSRF bypasses permit internal URL access
mcp-searxng is a Model Context Protocol server that gives AI assistants web search and URL-reading capabilities through SearXNG. Prior to 1.2.0, the web_url_read URL policy in src/url-reader.ts can be bypassed while MCP_HTTP_HARDEN is enabled and MCP_HTTP_ALLOW_PRIVATE_URLS is not enabled because redirect targets are not revalidated, 0.0.0.0 is not classified as an internal address, and IPv4-mapped IPv6 literals canonicalized to hexadecimal form are not recognized. These inputs allow an attacker-influenced tool call to make the MCP server fetch loopback or internal HTTP resources and return content from local services, private APIs, service-mesh endpoints, or cloud metadata endpoints. The separate hostname-to-private-address case addressed by the earlier partial fix is not part of these residual bypasses. This issue is fixed in version 1.2.0.
Attack profile
How easy it is to exploit
- Attack vector
- Local
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.3
mcp-searxng hardened-mode SSRF bypasses permit internal URL access
mcp-searxng is a Model Context Protocol server that gives AI assistants web search and URL-reading capabilities through SearXNG. Prior to 1.2.0, the web_url_read URL policy in src/url-reader.ts can be bypassed while MCP_HTTP_HARDEN is enabled and MCP_HTTP_ALLOW_PRIVATE_URLS is not enabled because redirect targets are not revalidated, 0.0.0.0 is not classified as an internal address, and IPv4-mapped IPv6 literals canonicalized to hexadecimal form are not recognized. These inputs allow an attacker-influenced tool call to make the MCP server fetch loopback or internal HTTP resources and return content from local services, private APIs, service-mesh endpoints, or cloud metadata endpoints. The separate hostname-to-private-address case addressed by the earlier partial fix is not part of these residual bypasses. This issue is fixed in version 1.2.0.
- Record
CVE-2026-54689- CVSS 3.1
- 6.3 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N - Weakness
- CWE-200, CWE-918
- Updated
- 2026-11-02
EUVDEUVD-2026-78921
6.3
mcp-searxng is a Model Context Protocol server that gives AI assistants web search and URL-reading capabilities through SearXNG. Prior to 1.2.0, the web_url_read URL policy in src/url-reader.ts can be bypassed while MCP_HTTP_HARDEN is enabled and MCP_HTTP_ALLOW_PRIVATE_URLS is not enabled because redirect targets are not revalidated, 0.0.0.0 is not classified as an internal address, and IPv4-mapped IPv6 literals canonicalized to hexadecimal form are not recognized. These inputs allow an attacker-influenced tool call to make the MCP server fetch loopback or internal HTTP resources and return content from local services, private APIs, service-mesh endpoints, or cloud metadata endpoints. The separate hostname-to-private-address case addressed by the earlier partial fix is not part of these residual bypasses. This issue is fixed in version 1.2.0.
- Record
EUVD-2026-78921- CVSS 3.1
- 6.3 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-wppf-h75h-6pm6
6.3
SearXNG MCP Server: Additional hardened-mode SSRF bypasses
Summary
mcp-searxng has a hardened-mode URL-reading feature intended to prevent web_url_read from reaching private or internal network resources.
PR #79 appears to address one SSRF class: hostnames that resolve to private or internal addresses under hardened mode. I tested PR #79 locally and confirmed that it blocks the DNS-resolves-to-loopback case.
However, several other hardened-mode SSRF bypasses still appear to remain:
- Redirects from an allowed first-hop URL to a loopback/internal URL are followed without re-validating the redirect target.
0.0.0.0is not treated as an internal/special address.- IPv4-mapped IPv6 literals can bypass private-address checks after URL canonicalization.
With hardened mode enabled and private URLs not explicitly allowed, web_url_read was still able to fetch and return content from a local loopback sentinel service in all three cases.
Tested configuration
MCP_HTTP_HARDEN=true
MCP_HTTP_ALLOW_PRIVATE_URLS unset
The MCP server was driven over stdio.
The test target was a harmless internal sentinel HTTP service bound to:
127.0.0.1:6789
The sentinel response contained:
INTERNAL_SECRET_DATA__mcp_searxng_ssrf_path2
Relationship to PR #79
I tested PR #79 locally:
- PR:
fix(url-reader): block DNS-rebinding SSRF via socket-level lookup guard (CWE-918) #79 - PR commit tested:
e55d28e7be6786a71cd7a0eaf13d3ec9d0b734d4 - Base issue class: CWE-918 / SSRF in
web_url_read - Hardened mode: enabled
Observed results:
Case Result on PR #79
-------------------------------------------------------------
DNS hostname resolving to 127.0.0.1 blocked
0.0.0.0 BYPASS
[::ffff:127.0.0.1] BYPASS
redirect from non-private IP to 127.0.0.1 BYPASS
So PR #79 is a useful fix, but it does not fully close hardened-mode internal URL access.
Root cause
1. Redirect targets are not re-validated
The URL policy appears to be applied to the initial URL, but redirect targets are followed by fetch() without applying the same policy to each hop.
A non-private attacker-controlled first-hop URL can respond with:
302 Location: http://127.0.0.1:6789/secret
The request is then followed to loopback.
This is independent of DNS rebinding. Even if the initial host is a non-private IP literal, the redirect can still pivot to 127.0.0.1.
2. 0.0.0.0 is not treated as internal
0.0.0.0 is not currently blocked by the private IPv4 predicate. On Linux, connecting to 0.0.0.0:<port> can reach a local service bound on loopback or wildcard interfaces.
In my test, this URL returned the sentinel from the local loopback service:
http://0.0.0.0:6789/secret
3. IPv4-mapped IPv6 canonicalization bypass
The current IPv4-mapped IPv6 handling appears to expect a dotted-decimal tail such as:
::ffff:127.0.0.1
However, Node's WHATWG URL parser canonicalizes:
new URL("http://[::ffff:127.0.0.1]/").hostname
to:
[::ffff:7f00:1]
As a result, regex logic that expects the dotted-decimal form can miss the private IPv4-mapped address.
In my test, this URL returned the loopback sentinel:
http://[::ffff:127.0.0.1]:6789/secret
Impact
This is a hardened-mode SSRF bypass.
The sentinel service in the PoC is intentionally local and harmless. It represents an internal-only service reachable from the MCP server host.
In real deployments, the same class of issue could allow web_url_read to reach:
- local admin panels bound to loopback;
- Redis, Elasticsearch, or other local HTTP-like services;
- internal HTTP APIs on private networks;
- service mesh endpoints;
- cloud metadata endpoints, depending on routing and environment.
This is especially relevant for MCP deployments because tool calls may be selected by an AI assistant. If untrusted content can influence tool…
- Record
GHSA-wppf-h75h-6pm6- CVSS 3.1
- 6.3 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N - Weakness
- CWE-200, CWE-918
- Updated
- 2026-11-02
NVD
6.3
mcp-searxng is a Model Context Protocol server that gives AI assistants web search and URL-reading capabilities through SearXNG. Prior to 1.2.0, the web_url_read URL policy in src/url-reader.ts can be bypassed while MCP_HTTP_HARDEN is enabled and MCP_HTTP_ALLOW_PRIVATE_URLS is not enabled because redirect targets are not revalidated, 0.0.0.0 is not classified as an internal address, and IPv4-mapped IPv6 literals canonicalized to hexadecimal form are not recognized. These inputs allow an attacker-influenced tool call to make the MCP server fetch loopback or internal HTTP resources and return content from local services, private APIs, service-mesh endpoints, or cloud metadata endpoints. The separate hostname-to-private-address case addressed by the earlier partial fix is not part of these residual bypasses. This issue is fixed in version 1.2.0.
- Record
CVE-2026-54689- CVSS 3.1
- 6.3 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N - Weakness
- CWE-200, CWE-918
- Updated
- 2026-11-02
OSV
6.3
mcp-searxng hardened-mode SSRF bypasses permit internal URL access
mcp-searxng is a Model Context Protocol server that gives AI assistants web search and URL-reading capabilities through SearXNG. Prior to 1.2.0, the web_url_read URL policy in src/url-reader.ts can be bypassed while MCP_HTTP_HARDEN is enabled and MCP_HTTP_ALLOW_PRIVATE_URLS is not enabled because redirect targets are not revalidated, 0.0.0.0 is not classified as an internal address, and IPv4-mapped IPv6 literals canonicalized to hexadecimal form are not recognized. These inputs allow an attacker-influenced tool call to make the MCP server fetch loopback or internal HTTP resources and return content from local services, private APIs, service-mesh endpoints, or cloud metadata endpoints. The separate hostname-to-private-address case addressed by the earlier partial fix is not part of these residual bypasses. This issue is fixed in version 1.2.0.
- Record
CVE-2026-54689- CVSS 3.1
- 6.3 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N - Weakness
- CWE-200, CWE-918
- Updated
- 2026-11-02
OSVGHSA-wppf-h75h-6pm6
6.3
SearXNG MCP Server: Additional hardened-mode SSRF bypasses
Summary
mcp-searxng has a hardened-mode URL-reading feature intended to prevent web_url_read from reaching private or internal network resources.
PR #79 appears to address one SSRF class: hostnames that resolve to private or internal addresses under hardened mode. I tested PR #79 locally and confirmed that it blocks the DNS-resolves-to-loopback case.
However, several other hardened-mode SSRF bypasses still appear to remain:
- Redirects from an allowed first-hop URL to a loopback/internal URL are followed without re-validating the redirect target.
0.0.0.0is not treated as an internal/special address.- IPv4-mapped IPv6 literals can bypass private-address checks after URL canonicalization.
With hardened mode enabled and private URLs not explicitly allowed, web_url_read was still able to fetch and return content from a local loopback sentinel service in all three cases.
Tested configuration
MCP_HTTP_HARDEN=true
MCP_HTTP_ALLOW_PRIVATE_URLS unset
The MCP server was driven over stdio.
The test target was a harmless internal sentinel HTTP service bound to:
127.0.0.1:6789
The sentinel response contained:
INTERNAL_SECRET_DATA__mcp_searxng_ssrf_path2
Relationship to PR #79
I tested PR #79 locally:
- PR:
fix(url-reader): block DNS-rebinding SSRF via socket-level lookup guard (CWE-918) #79 - PR commit tested:
e55d28e7be6786a71cd7a0eaf13d3ec9d0b734d4 - Base issue class: CWE-918 / SSRF in
web_url_read - Hardened mode: enabled
Observed results:
Case Result on PR #79
-------------------------------------------------------------
DNS hostname resolving to 127.0.0.1 blocked
0.0.0.0 BYPASS
[::ffff:127.0.0.1] BYPASS
redirect from non-private IP to 127.0.0.1 BYPASS
So PR #79 is a useful fix, but it does not fully close hardened-mode internal URL access.
Root cause
1. Redirect targets are not re-validated
The URL policy appears to be applied to the initial URL, but redirect targets are followed by fetch() without applying the same policy to each hop.
A non-private attacker-controlled first-hop URL can respond with:
302 Location: http://127.0.0.1:6789/secret
The request is then followed to loopback.
This is independent of DNS rebinding. Even if the initial host is a non-private IP literal, the redirect can still pivot to 127.0.0.1.
2. 0.0.0.0 is not treated as internal
0.0.0.0 is not currently blocked by the private IPv4 predicate. On Linux, connecting to 0.0.0.0:<port> can reach a local service bound on loopback or wildcard interfaces.
In my test, this URL returned the sentinel from the local loopback service:
http://0.0.0.0:6789/secret
3. IPv4-mapped IPv6 canonicalization bypass
The current IPv4-mapped IPv6 handling appears to expect a dotted-decimal tail such as:
::ffff:127.0.0.1
However, Node's WHATWG URL parser canonicalizes:
new URL("http://[::ffff:127.0.0.1]/").hostname
to:
[::ffff:7f00:1]
As a result, regex logic that expects the dotted-decimal form can miss the private IPv4-mapped address.
In my test, this URL returned the loopback sentinel:
http://[::ffff:127.0.0.1]:6789/secret
Impact
This is a hardened-mode SSRF bypass.
The sentinel service in the PoC is intentionally local and harmless. It represents an internal-only service reachable from the MCP server host.
In real deployments, the same class of issue could allow web_url_read to reach:
- local admin panels bound to loopback;
- Redis, Elasticsearch, or other local HTTP-like services;
- internal HTTP APIs on private networks;
- service mesh endpoints;
- cloud metadata endpoints, depending on routing and environment.
This is especially relevant for MCP deployments because tool calls may be selected by an AI assistant. If untrusted content can influence tool…
- Record
GHSA-wppf-h75h-6pm6- CVSS 3.1
- 6.3 Medium
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C/C:H/I:N/A:N - Weakness
- CWE-200, CWE-918
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
mcp-searxngnpm |
before 1.2.1 | 1.2.1 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-54689 is a medium vulnerability (CVSS 6.3) in Ihor-sokoliuk Mcp-searxng, published August 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.19%, the 8th percentile. Fixed in mcp-searxng 1.2.1.
References
github.com/ihor-sokoliuk/mcp-searxng/security/advisories/GHSA-wppf-h75h-6pm6
github.com/ihor-sokoliuk/mcp-searxng/pull/79
github.com/ihor-sokoliuk/mcp-searxng/commit/48e5ecdcb4166a60b94c252dbe74b0a318110ac4
github.com/ihor-sokoliuk/mcp-searxng/releases/tag/v1.2.0
github.com/ihor-sokoliuk/mcp-searxng/releases/tag/v1.2.1
github.com/advisories/GHSA-wppf-h75h-6pm6
github.com/CVEProject/cvelistV5/tree/main/cves/2026/54xxx/CVE-2026-54689.json
nvd.nist.gov/vuln/detail/CVE-2026-54689
github.com/ihor-sokoliuk/mcp-searxng
Left out here: the rest of 2 source descriptions. The JSON record has them.