security: fix SSE CORS wildcard and add token authentication#48
security: fix SSE CORS wildcard and add token authentication#48
Conversation
Co-authored-by: cfc4n <709947+cfc4n@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR hardens the SSE (-l / listen) mode by preventing cross-origin browser reads of the SSE stream and by requiring a shared secret token for all SSE requests, addressing the reported “No Authentication + CORS: *” vulnerability.
Changes:
- Add SSE auth token support (config + CLI flag), including auto-generation when listening in SSE mode.
- Wrap the SSE HTTP handler with middleware that strips
Access-Control-Allow-Origin: *and enforces token authentication. - Add tests covering the SSE middleware behavior and token auto-generation.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| pkg/server/server.go | Implements CORS header stripping, token auth middleware, token generation, and uses a custom http.Server for SSE mode. |
| pkg/server/server_test.go | Adds tests for auth/CORS middleware and token auto-generation behavior. |
| pkg/config/config.go | Introduces MoLingConfig.AuthToken configuration field. |
| cli/cmd/root.go | Adds --token/-t flag to configure SSE authentication token. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
pkg/server/server.go
Outdated
| bearerToken := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") | ||
| queryToken := r.URL.Query().Get("token") | ||
| tokenBytes := []byte(token) | ||
| validBearer := subtle.ConstantTimeCompare([]byte(bearerToken), tokenBytes) == 1 | ||
| validQuery := subtle.ConstantTimeCompare([]byte(queryToken), tokenBytes) == 1 |
|
@copilot 解决代码冲突: |
Co-authored-by: cfc4n <709947+cfc4n@users.noreply.github.com>
... Resolved in b17aa95. The conflicts were caused by master adding |
Co-authored-by: cfc4n <709947+cfc4n@users.noreply.github.com>
When run in SSE mode (
-l), the HTTP server had no authentication andmcp-gohardcodedAccess-Control-Allow-Origin: *, allowing any webpage to connect viaEventSource, read the SSE stream, and steal thesessionId.Changes
CORS stripping —
corsRemoverResponseWriterwrapshttp.ResponseWriterto interceptWriteHeader/Writeand delete theAccess-Control-Allow-Origin: *header injected by mcp-go before it reaches the client. Forwardshttp.Flusherso SSE streaming is unaffected.Token authentication —
sseSecurityMiddlewarerequires a bearer token on every request, accepted asAuthorization: ****** (scheme strictly enforced — bare token in Authorization header is rejected) or?token=. Usescrypto/subtle.ConstantTimeCompare` to prevent timing attacks.Token provisioning —
NewMoLingServerauto-generates a 32-hex-char token (crypto/rand, 16 bytes) whenListenAddris set and no token is configured. Token and ready-to-use URL are written to stdout only via a console-only logger — never persisted to the log file.Middleware chain —
sseSecurityMiddleware → requireJSONContentType → SSEServer. TherequireJSONContentTypelayer (from security: enforce application/json Content-Type on /message to close CORS preflight bypass #47) rejects POST requests with non-application/jsonContent-Types, ensuring cross-origin POSTs always trigger a CORS preflight.Config & CLI —
MoLingConfig.AuthTokenfield, configurable via--token/-tflag to pin a fixed token instead of auto-generating one.Original prompt
This section details on the original issue you should resolve
<issue_title>vulnerability:SSE No Authentication + CORS: *</issue_title>
<issue_description>This vulnerability is found by Songwu security researcher,Zeyu Luo security researcher, Dr. CAO Yinfeng, Kevin(The Hong Kong Polytechnic University / HKCT Institute of Higher Education)
vulnerability description
When moling is started in SSE mode with the -l flag, the HTTP server does not implement any authentication mechanism. In addition, the underlying mcp-go library hardcodes Access-Control-Allow-Origin: * in the HTTP response headers for the /sse endpoint.
Under normal circumstances, the browser’s Same-Origin Policy (SOP) would prevent scripts from site A from reading responses from site B. However, Access-Control-Allow-Origin: * explicitly tells the browser that “any website is allowed to read my response.” As a result, any webpage can use EventSource to connect to /sse and fully read the SSE stream, including the sessionId contained in it.
POC