From 85379ec36c9ae47038e221c4c6b4a82b24ac261a Mon Sep 17 00:00:00 2001 From: airano Date: Wed, 18 Feb 2026 16:24:04 +0330 Subject: [PATCH] fix(security): validate Bearer token value in MCP endpoints, not just presence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously any Bearer token (even invalid) passed the HTTP middleware and got a session with access to tools/list and resources/list. Now the OAuthRequiredMiddleware validates tokens against master key, API keys, and OAuth JWT before allowing initialize. Also fixes: - WordPress Advanced env prefix: WORDPRESS_ → WORDPRESS_ADVANCED_ in docs - Bump version to 3.0.1 Co-Authored-By: Claude Opus 4.6 --- DOCKER_README.md | 2 +- core/dashboard/routes.py | 2 +- core/templates/dashboard/login.html | 2 +- docs/getting-started.md | 2 +- pyproject.toml | 2 +- server.py | 46 +++++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 5 deletions(-) diff --git a/DOCKER_README.md b/DOCKER_README.md index e6f698a..d6d58d8 100644 --- a/DOCKER_README.md +++ b/DOCKER_README.md @@ -108,7 +108,7 @@ Add more sites with `SITE2`, `SITE3`, etc. See [full configuration guide](https: |--------|-------|------------| | WordPress | 67 | `WORDPRESS_` | | WooCommerce | 28 | `WOOCOMMERCE_` | -| WordPress Advanced | 22 | `WORDPRESS_` | +| WordPress Advanced | 22 | `WORDPRESS_ADVANCED_` | | Gitea | 56 | `GITEA_` | | n8n | 56 | `N8N_` | | Supabase | 70 | `SUPABASE_` | diff --git a/core/dashboard/routes.py b/core/dashboard/routes.py index 889776c..2ccdc63 100644 --- a/core/dashboard/routes.py +++ b/core/dashboard/routes.py @@ -1995,7 +1995,7 @@ def _get_project_version() -> str: return line.split("=")[1].strip().strip('"').strip("'") except Exception: pass - return "3.0.0" + return "3.0.1" def get_about_info() -> dict: diff --git a/core/templates/dashboard/login.html b/core/templates/dashboard/login.html index f5b6ca3..0dafedb 100644 --- a/core/templates/dashboard/login.html +++ b/core/templates/dashboard/login.html @@ -138,7 +138,7 @@

- MCP Hub v{{ version|default('3.0.0') }} + MCP Hub v{{ version|default('3.0.1') }}

diff --git a/docs/getting-started.md b/docs/getting-started.md index 10ec351..f2b37dd 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -319,7 +319,7 @@ MCP Hub supports **Open Dynamic Client Registration** (RFC 7591). ChatGPT can au |--------|-------|------------| | WordPress | 67 | `WORDPRESS_` | | WooCommerce | 28 | `WOOCOMMERCE_` | -| WordPress Advanced | 22 | `WORDPRESS_` (same sites, advanced ops) | +| WordPress Advanced | 22 | `WORDPRESS_ADVANCED_` | | Gitea | 56 | `GITEA_` | | n8n | 56 | `N8N_` | | Supabase | 70 | `SUPABASE_` | diff --git a/pyproject.toml b/pyproject.toml index 3e35376..c9f84bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "mcphub-server" -version = "3.0.0" +version = "3.0.1" description = "AI-native management hub for WordPress, WooCommerce, and self-hosted services via Model Context Protocol (MCP)" authors = [ {name = "MCP Hub", email = "contact@mcphub.dev"} diff --git a/server.py b/server.py index 07c4bd6..cd469c8 100644 --- a/server.py +++ b/server.py @@ -4053,8 +4053,54 @@ def create_multi_endpoint_app(transport: str = "streamable-http"): }, ) + # Validate the token value (not just presence) + token = auth_header.removeprefix("Bearer ").strip() + if token and not self._is_valid_token(token): + base_url = get_oauth_base_url(request) + resource_metadata_url = f"{base_url}/.well-known/oauth-protected-resource" + logger.warning(f"MCP OAuth: Invalid token for {path}") + + return Response( + content='{"error": "invalid_token", "error_description": "Bearer token is invalid"}', + status_code=401, + media_type="application/json", + headers={ + "WWW-Authenticate": f'Bearer resource_metadata="{resource_metadata_url}", error="invalid_token"', + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Headers": "Authorization, Content-Type", + "Access-Control-Expose-Headers": "WWW-Authenticate", + }, + ) + return await call_next(request) + @staticmethod + def _is_valid_token(token: str) -> bool: + """Check if a Bearer token is recognized by any auth backend.""" + # 1. Master API key + if auth_manager.validate_master_key(token): + return True + + # 2. Per-project API key (any valid key, skip project/scope check) + if token.startswith("cmp_"): + key_hash = api_key_manager._hash_key(token) + for key in api_key_manager.keys.values(): + if key.key_hash == key_hash and key.is_valid(): + return True + return False + + # 3. OAuth JWT token + try: + from core.oauth import get_token_manager + + token_manager = get_token_manager() + if token_manager.validate_access_token(token): + return True + except Exception: + pass + + return False + # Create MCP instances system_mcp = create_system_mcp() # Phase X.3 - System endpoint wp_mcp = create_wordpress_mcp()