Skip to content

SSE mode exposes unauthenticated endpoint with CORS wildcard, leaking sessionId to cross-origin attackers

Critical
cfc4n published GHSA-qpgh-hp5g-4vwp Jun 27, 2026

Package

github.com/gojue/moling

Affected versions

<= 0.4.0

Patched versions

0.5.0

Description

Summary

When moling is started in SSE (Server-Sent Events) mode using the -l flag, the HTTP server does not implement any authentication mechanism. Additionally, the underlying mcp-go library hardcodes Access-Control-Allow-Origin: * in the HTTP response headers for the /sse endpoint.

This combination allows any web page—served from any origin—to establish a cross-origin EventSource connection to the /sse endpoint, fully read the SSE stream, and extract the sessionId, which can subsequently be used to perform unauthorized actions against the server.

Vulnerability Details

Under normal browser security rules, the Same-Origin Policy (SOP) prevents scripts on evil-attacker.com from reading responses from 127.0.0.1. However, the presence of Access-Control-Allow-Origin: * explicitly instructs the browser to lift this restriction, allowing full cross-origin reads of the SSE stream.

Attack scenario:

  1. Victim runs moling -l 127.0.0.1:6789
  2. Victim visits a malicious web page (from any origin)
  3. The malicious page opens an EventSource to http://127.0.0.1:6789/sse
  4. The browser permits this due to Access-Control-Allow-Origin: *
  5. The malicious page reads the endpoint event and extracts the sessionId
  6. The attacker uses the leaked sessionId to send arbitrary commands to the MCP server

Proof of Concept (simplified):

const es = new EventSource('http://127.0.0.1:6789/sse');
es.addEventListener('endpoint', (e) => {
  const sessionId = e.data.split('sessionId=')[1];
  console.log('Leaked sessionId:', sessionId);
  // Attacker can now POST to /message?sessionId=<leaked> to control the server
});

Root Cause

  • No authentication: The /sse and /message HTTP endpoints accept all requests without any credential verification.
  • Hardcoded CORS wildcard: The mcp-go dependency unconditionally sets Access-Control-Allow-Origin: *, bypassing the browser's Same-Origin Policy.

Impact

An attacker who can trick a victim running moling in SSE mode into visiting a malicious web page can:

  • Steal the sessionId credential from the SSE stream
  • Send arbitrary MCP tool calls to the local moling server
  • Potentially achieve local file read/write, command execution, or other actions depending on configured MCP tools

🔧 Patches / Fix

Fixed in PR #48 — commit ae07f704.

Changes implemented:

  1. CORS stripping — Introduced corsRemoverResponseWriter that wraps http.ResponseWriter to intercept and remove the Access-Control-Allow-Origin: * header injected by mcp-go before responses reach the client. SSE streaming (http.Flusher) is preserved.
  2. Token authentication — Added sseSecurityMiddleware that requires a bearer token on every request, accepted via Authorization: Bearer <token> header or ?token= query parameter. Uses crypto/subtle.ConstantTimeCompare to prevent timing attacks.
  3. Token provisioningNewMoLingServer auto-generates a 32-hex-character token (crypto/rand, 16 bytes) when ListenAddr is set and no token is configured. The token and a ready-to-use URL are printed to stdout only—never persisted to log files.
  4. Middleware chain — Enforces sseSecurityMiddleware → requireJSONContentType → SSEServer. The requireJSONContentType layer rejects POST requests without application/json Content-Type, ensuring cross-origin POSTs always trigger a CORS preflight.
  5. Config & CLI — Added MoLingConfig.AuthToken field, configurable via --token / -t CLI flag.

🛡️ Workarounds

Users who cannot upgrade immediately should:

  • Avoid using SSE mode (-l flag) in environments where the machine may be exposed to untrusted web content.
  • Use a firewall or network policy to restrict access to the listening port (e.g., bind only to 127.0.0.1 and block external access).
  • Avoid browsing untrusted websites while moling is running in SSE mode.

👥 Credits / Acknowledgements

This vulnerability was discovered and responsibly reported by:

  • Songwu (security researcher)
  • Zeyu Luo (security researcher)
  • Dr. CAO Yinfeng
  • Kevin

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
Required
Scope
Changed
Confidentiality
High
Integrity
High
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:L

CVE ID

CVE-2026-62863

Weaknesses

No CWEs