From 8fe50a793dc8d23df77a268985c8448713667e1e Mon Sep 17 00:00:00 2001 From: adityamparikh Date: Sat, 2 May 2026 16:57:44 -0400 Subject: [PATCH] fix(security): replace permissive CORS wildcard with explicit allowlist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HTTP CORS configuration used setAllowedOriginPatterns("*") with allowCredentials=true, which is Spring's escape hatch around the browser rule that wildcards can't be used with credentials (MDN CORS spec). Replace with the strict setAllowedOrigins API and a configurable allowlist that defaults to the MCP Inspector's local proxy port. Methods and headers also tightened to the explicit set used by the Streamable HTTP transport per the MCP specification, replacing "*" wildcards. Operators add additional origins via the MCP_CORS_ALLOWED_ORIGINS env var or the mcp.cors.allowed-origins property. Refs: - MDN CORS — Credentialed requests and wildcards - CWE-942: Permissive Cross-domain Policy with Untrusted Domains - OWASP HTML5 Security Cheat Sheet (CORS) Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: adityamparikh --- .../security/HttpSecurityConfiguration.java | 19 ++++++++++++++++--- .../resources/application-http.properties | 4 ++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java b/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java index ac0c3ae7..5a4392d7 100644 --- a/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java +++ b/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java @@ -39,6 +39,9 @@ class HttpSecurityConfiguration { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri:}") private String issuerUrl; + @Value("${mcp.cors.allowed-origins}") + private List allowedOrigins; + @Bean @ConditionalOnProperty(name = "http.security.enabled", havingValue = "true", matchIfMissing = true) SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -69,9 +72,19 @@ SecurityFilterChain unsecured(HttpSecurity http) throws Exception { public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOriginPatterns(List.of("*")); - configuration.setAllowedMethods(List.of("*")); - configuration.setAllowedHeaders(List.of("*")); + // Use the strict setAllowedOrigins API (not setAllowedOriginPatterns) so the + // browser-spec rule that wildcards cannot be combined with credentials is + // enforced. + // Origins are configurable via the mcp.cors.allowed-origins property + // (env: MCP_CORS_ALLOWED_ORIGINS) and default to the MCP Inspector's local + // proxy. + configuration.setAllowedOrigins(allowedOrigins); + // Only the HTTP methods used by the MCP Streamable HTTP transport. + configuration.setAllowedMethods(List.of("GET", "POST", "DELETE", "OPTIONS")); + // Only the headers the MCP specification requires for the Streamable HTTP + // transport. + configuration.setAllowedHeaders( + List.of("Authorization", "Content-Type", "Mcp-Session-Id", "MCP-Protocol-Version", "Last-Event-ID")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/src/main/resources/application-http.properties b/src/main/resources/application-http.properties index 95daa2eb..03fcc312 100644 --- a/src/main/resources/application-http.properties +++ b/src/main/resources/application-http.properties @@ -13,6 +13,10 @@ spring.docker.compose.enabled=true spring.security.oauth2.resourceserver.jwt.issuer-uri=${OAUTH2_ISSUER_URI:https://your-auth0-domain.auth0.com/} # Security toggle - set to true to enable OAuth2 authentication, false to bypass http.security.enabled=${HTTP_SECURITY_ENABLED:false} +# Comma-separated list of allowed CORS origins for the MCP HTTP endpoint. +# Defaults to MCP Inspector's local proxy. Add additional origins (browser-based +# MCP clients, internal dashboards) as needed. Do NOT use "*" with credentials. +mcp.cors.allowed-origins=${MCP_CORS_ALLOWED_ORIGINS:http://localhost:6274,http://127.0.0.1:6274} # observability management.endpoints.web.exposure.include=health,sbom,metrics,info,loggers,prometheus # Enable @Observed annotation support for custom spans