GHSA-j3vx-cx2r-pvg8: Network-AI: Unauthenticated Cross-Origin MCP Tool Invocation via Empty Default Secret
Unauthenticated Cross-Origin MCP Tool Invocation via Empty Default Secret| Field            | Value |
| ---------------- | ----- |
| Repository       | Jovancoding/Network-AI |
| Affected version | v5.4.4 (commit c12686e181f231cf8d7bcf836a96d78f0f0877ac) |SummaryThe MCP SSE server defaults to an empty secret (`process.env['NETWORK_AI_MCP_SECRET'] ?? ''` at `bin/mcp-server.ts:89`), which causes `_isAuthorized` (`lib/mcp-transport-sse.ts:254`) to return `true` unconditionally for every request — no `Authorization` header is required. Simultaneously, `_handleRequest` sets `Access-Control-Allow-Origin: *` (`lib/mcp-transport-sse.ts:272`) on every response, so a cross-origin browser fetch can read the result without restriction. An unauthenticated attacker who can lure a user to a malicious web page can invoke all 22 exposed MCP tools — including `config_set`, `agent_spawn`, and `blackboard_write` — against a default-configured localhost server.Affected Code`bin/mcp-server.ts:89` — default secret resolves to empty string, enabling open access`lib/mcp-transport-sse.ts:254` — auth guard short-circuits to `true` when secret is falsy`lib/mcp-transport-sse.ts:272` — wildcard CORS header applied unconditionally before any auth check`lib/mcp-transport-sse.ts:367-368` — authenticated path dispatches parsed JSON-RPC frame directly to `handleRPC` with no further caller validationAny cross-origin browser request reaches `handleRPC` because `_isAuthorized` returns `true` (empty secret) and the `Access-Control-Allow-Origin: *` header lets the browser expose the response to the calling script.Proof of Concept**Environment**Network-AI v5.4.4 (latest)Docker container bound to `127.0.0.1:3001`Python 3 + `requests`**poc.py****Output****Verified conditions**`OPTIONS /mcp` → 204, `Access-Control-Allow-Origin: *` — browser preflight accepted by server`POST /mcp` (no Authorization header) → 200, `isError: false` — `config_set` executed without credentialsResponse `Access-Control-Allow-Origin: *` — response is readable by the calling script in a browser context, confirming the attack is viable from a cross-origin malicious pageImpactAny web page visited by a user who has the Network-AI MCP server running locally (default port 3001, no secret) can silently invoke all 22 MCP tools without credentials. Verified impact includes arbitrary orchestrator configuration mutation (`config_set`); the same vector applies to `agent_spawn` (spawning arbitrary agents), `blackboard_write` / `blackboard_delete` (corrupting shared agent state), and `token_create` / `token_revoke` (tampering with token management). Confidentiality impact is limited to data readable via MCP tools (blackboard contents, audit log queries); integrity impact is high because core orchestrator state can be overwritten; availability impact is low (service continues running but with attacker-controlled configuration).Remediation**Require a non-empty secret at startup**: in `bin/mcp-server.ts`, reject launch when `args.secret` is empty and `--stdio` is not set:**Restrict CORS to localhost origins only**: in `lib/mcp-transport-sse.ts:_handleRequest`, replace the wildcard with an allowlist:**Move CORS headers after the auth check** so a rejected request never advertises cross-origin access, or apply CORS only on the SSE endpoint (`/sse`) if cross-origin streaming is needed and not on `/mcp`.
CVSS v3.1: 7.6