You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An attacker-controlled web page instructs the victim's browser to open GET https://internal-mcp-server/sse. Because Access-Control-Allow-Origin: * allows cross-origin SSE reads, the attacker's page receives the endpoint event — which contains the session ID. The attacker can then POST to that endpoint from their page using the victim's browser as a relay.
In the SDK, the transport layer should not own CORS policy. Server implementors who need cross-origin access can add a CORS filter at the servlet filter or Spring Security layer.
The product uses a web-client protection mechanism such as a Content Security Policy (CSP) or cross-domain policy file, but the policy includes untrusted domains with which the web client is allowed to communicate.
Learn more on MITRE.
Summary
Hardcoded Wildcard CORS (Access-Control-Allow-Origin: * )
Attack Scenario
An attacker-controlled web page instructs the victim's browser to open GET https://internal-mcp-server/sse. Because Access-Control-Allow-Origin: * allows cross-origin SSE reads, the attacker's page receives the endpoint event — which contains the session ID. The attacker can then POST to that endpoint from their page using the victim's browser as a relay.
Comparison with python-sdk
No Access-Control-Allow-Origin header is emitted by either Python transport. The browser's default same-origin policy remains in full effect.
https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/sse.py
https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/streamable_http.py
Recommendation
In the SDK, the transport layer should not own CORS policy. Server implementors who need cross-origin access can add a CORS filter at the servlet filter or Spring Security layer.
Reference