{"id":"CVE-2026-48814","aliases":["EUVD-2026-37787","GHSA-r78r-rwrf-rjwp"],"status":"published","title":"Network-AI:  Empty default secret still authorizes all requests (Incomplete fix for CVE-2026-46701)","description":"Network-AI is a TypeScript/Node.js multi-agent orchestrator. In versions 5.7.1 and earlier, the MCP SSE server allows unauthenticated cross-origin MCP tool invocation due to an empty default secret. This issue was partially addressed by CVE-2026-46701 in version 5.4.5 by closing the CORS flaw (with Access-Control-Allow-Origin now set only for localhost origins), but the empty-default-secret flaw described in the title remained: the SSE MCP server still defaulted to an empty secret, _isAuthorized() still returned true when the secret was empty, and a non-loopback bind only produced a warning. As a result, the server still ran fully unauthenticated by default. Any non-browser caller (for example, curl, SSRF, or a 0.0.0.0 bind) could invoke all 22 MCP tools (config_set, agent_spawn, blackboard_write, token_*) with no credentials. This issue was fixed in version 5.7.2.","severity":{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-09","score":0.00445,"percentile":0.38954,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-306"],"published":"2026-06-17T19:42:30Z","modified":"2026-10-28T02:30:34Z","fixes":[{"ecosystem":"npm","package":"network-ai","fixed_in":["5.7.2"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"network-ai","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"5.7.1"},{"fixed":"5.7.2"}]}]},{"source":"osv","ecosystem":"npm","package":"network-ai","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"5.7.2"}]}]}],"products":[{"vendor":"jovancoding","product":"network-ai"}],"references":[{"url":"https://github.com/Jovancoding/Network-AI/security/advisories/GHSA-r78r-rwrf-rjwp","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/Jovancoding/Network-AI/releases/tag/v5.7.2","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-j3vx-cx2r-pvg8","tags":["x_refsource_MISC","advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-48814","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-r78r-rwrf-rjwp"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/48xxx/CVE-2026-48814.json","tags":["advisory"]},{"url":"https://github.com/Jovancoding/Network-AI","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-48814","title":"Network-AI:  Empty default secret still authorizes all requests (Incomplete fix for CVE-2026-46701)","description":"Network-AI is a TypeScript/Node.js multi-agent orchestrator. In versions 5.7.1 and earlier, the MCP SSE server allows unauthenticated cross-origin MCP tool invocation due to an empty default secret. This issue was partially addressed by CVE-2026-46701 in version 5.4.5 by closing the CORS flaw (with Access-Control-Allow-Origin now set only for localhost origins), but the empty-default-secret flaw described in the title remained: the SSE MCP server still defaulted to an empty secret, _isAuthorized() still returned true when the secret was empty, and a non-loopback bind only produced a warning. As a result, the server still ran fully unauthenticated by default. Any non-browser caller (for example, curl, SSRF, or a 0.0.0.0 bind) could invoke all 22 MCP tools (config_set, agent_spawn, blackboard_write, token_*) with no credentials. This issue was fixed in version 5.7.2.","status":"published","published":"2026-06-17T19:42:30.415Z","modified":"2026-06-18T19:43:01.315Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical","assessor":"cna"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T13:50:49.872037Z"}],"euvd":[{"id":"EUVD-2026-37787","description":"Network-AI is a TypeScript/Node.js multi-agent orchestrator. In versions 5.7.1 and earlier, the MCP SSE server allows unauthenticated cross-origin MCP tool invocation due to an empty default secret. This issue was partially addressed by CVE-2026-46701 in version 5.4.5 by closing the CORS flaw (with Access-Control-Allow-Origin now set only for localhost origins), but the empty-default-secret flaw described in the title remained: the SSE MCP server still defaulted to an empty secret, _isAuthorized() still returned true when the secret was empty, and a non-loopback bind only produced a warning. As a result, the server still ran fully unauthenticated by default. Any non-browser caller (for example, curl, SSRF, or a 0.0.0.0 bind) could invoke all 22 MCP tools (config_set, agent_spawn, blackboard_write, token_*) with no credentials. This issue was fixed in version 5.7.2.","status":"published","published":"2026-06-17T19:42:30Z","modified":"2026-06-18T19:43:01Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical"}],"updated_at":"2026-11-02T18:20:36.276608Z"}],"ghsa":[{"id":"GHSA-r78r-rwrf-rjwp","title":"Network-AI: CVE-2026-46701 fix incomplete — empty default secret still authorizes all requests","description":"## Advisory / Disclosure\n\n# Network-AI — CVE-2026-46701 fix is incomplete: the \"Empty Default Secret\" unauth path survives\n\n**Target:** Jovancoding/Network-AI (npm `network-ai`), **latest v5.7.1**\n**Status:** the advisory (\"Unauthenticated Cross-Origin MCP Tool Invocation via Empty\nDefault Secret\") named three flaws. The fix (5.4.5) closed the **CORS** flaw\n(`Access-Control-Allow-Origin` is now set only for localhost origins), but left the\n**empty-default-secret** flaw the title is about: the SSE MCP server still defaults to an\nempty secret, `_isAuthorized()` still returns `true` when the secret is empty, and a\nnon-loopback bind only **warns**. So the server still runs **fully unauthenticated by\ndefault** — any non-browser caller (curl, SSRF, or a `0.0.0.0` bind) can invoke all 22 MCP\ntools (`config_set`, `agent_spawn`, `blackboard_write`, `token_*`) with no credentials.\n**Class:** CWE-306/CWE-862 Missing Authentication — incomplete fix.\n**Methodology:** M1 incomplete-fix audit (anchor = the 5.4.5 fix; sibling-walk on latest v5.7.1, executed).\n**Severity:** High (matches parent; the browser amplifier is removed, so exploitation now\nneeds non-browser reach — SSRF or a non-loopback bind, which the fix only warns about).\n\n## What the fix did and didn't do (verified on latest v5.7.1)\n| advisory flaw | latest v5.7.1 |\n|---|---|\n| wildcard CORS (`ACAO: *`) | **FIXED** — `lib/mcp-transport-sse.ts` sets `ACAO` only when `origin` matches `^https?://(localhost\\|127\\.0\\.0\\.1)(:\\d+)?$` |\n| empty default secret | **NOT FIXED** — `bin/mcp-server.ts`: `secret: process.env['NETWORK_AI_MCP_SECRET'] ?? ''` |\n| `_isAuthorized` open on empty secret | **NOT FIXED** — `if (!this._opts.secret) return true;` |\n| require secret / refuse unauth bind | **NOT DONE** — `listen()` only `process.stderr.write('… WARNING …')` on non-loopback bind, then listens anyway |\n\nThe advisory's remediation #1 (\"Require a non-empty secret at startup … `process.exit(1)`\")\nwas not implemented.\n\n## PoC (executed against the latest source, v5.7.1) — `poc/legend-networkai-empty-secret.ts`\nInstantiates the real `McpSseServer` from the latest `lib/` with a mock bridge and the\n**default (empty) secret**, then issues requests (run-log `poc/run-log.txt`):\n\n```\nPOST /mcp  no-auth, no-origin (curl/SSRF) -\u003e HTTP 200, dispatched=true\n   body: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"executed\":true,\"tool\":\"config_set\"}}\nPOST /mcp  Origin: evil.example.com        -\u003e ACAO=undefined   (CORS half fixed)\n```\nThe no-auth request passes `_isAuthorized` and reaches `handleRPC` (tool dispatched) — i.e.\nunauthenticated tool invocation persists on the latest release; only the browser-CORS read\namplifier was removed.\n\nRun: from a v5.7.1 checkout, `npm i` then\n`npx ts-node --transpile-only poc/legend-networkai-empty-secret.ts`.\n\n## Recommended fix\nImplement the advisory's remediation #1: refuse to start SSE mode with an empty secret\n(unless `--stdio`), and/or change `_isAuthorized` to fail closed (an empty configured\nsecret should mean \"deny\", not \"allow\"). The CORS allowlist alone does not authenticate\nnon-browser callers.\n\n## Precondition / honesty\nWith CORS now localhost-only, the drive-by *browser* attack is mitigated. The residual\nrequires a non-browser path to the port: an SSRF on the host, or the operator binding to a\nnon-loopback address (Docker/remote), which the fix only warns about. The empty secret\nremains the shipped default and `_isAuthorized` still authorizes it.\n\n## Credits\n\n@Kai Aizen / @SnailSploit — https://snailsploit.com","status":"published","published":"2026-06-19T13:34:24Z","modified":"2026-06-19T13:34:25Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T14:40:30.53004Z"}],"nvd":[{"id":"CVE-2026-48814","description":"Network-AI is a TypeScript/Node.js multi-agent orchestrator. In versions 5.7.1 and earlier, the MCP SSE server allows unauthenticated cross-origin MCP tool invocation due to an empty default secret. This issue was partially addressed by CVE-2026-46701 in version 5.4.5 by closing the CORS flaw (with Access-Control-Allow-Origin now set only for localhost origins), but the empty-default-secret flaw described in the title remained: the SSE MCP server still defaulted to an empty secret, _isAuthorized() still returned true when the secret was empty, and a non-loopback bind only produced a warning. As a result, the server still ran fully unauthenticated by default. Any non-browser caller (for example, curl, SSRF, or a 0.0.0.0 bind) could invoke all 22 MCP tools (config_set, agent_spawn, blackboard_write, token_*) with no credentials. This issue was fixed in version 5.7.2.","status":"published","published":"2026-06-17T20:17:22.26Z","modified":"2026-10-25T23:10:00.167Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical","assessor":"secondary"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T14:12:24.544761Z"}],"osv":[{"id":"CVE-2026-48814","title":"Network-AI:  Empty default secret still authorizes all requests (Incomplete fix for CVE-2026-46701)","description":"Network-AI is a TypeScript/Node.js multi-agent orchestrator. In versions 5.7.1 and earlier, the MCP SSE server allows unauthenticated cross-origin MCP tool invocation due to an empty default secret. This issue was partially addressed by CVE-2026-46701 in version 5.4.5 by closing the CORS flaw (with Access-Control-Allow-Origin now set only for localhost origins), but the empty-default-secret flaw described in the title remained: the SSE MCP server still defaulted to an empty secret, _isAuthorized() still returned true when the secret was empty, and a non-loopback bind only produced a warning. As a result, the server still ran fully unauthenticated by default. Any non-browser caller (for example, curl, SSRF, or a 0.0.0.0 bind) could invoke all 22 MCP tools (config_set, agent_spawn, blackboard_write, token_*) with no credentials. This issue was fixed in version 5.7.2.","status":"published","published":"2026-06-17T19:42:30.415Z","modified":"2026-10-28T02:30:34.094711067Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T15:45:06.701612Z"},{"id":"GHSA-r78r-rwrf-rjwp","title":"Network-AI: CVE-2026-46701 fix incomplete — empty default secret still authorizes all requests","description":"## Advisory / Disclosure\n\n# Network-AI — CVE-2026-46701 fix is incomplete: the \"Empty Default Secret\" unauth path survives\n\n**Target:** Jovancoding/Network-AI (npm `network-ai`), **latest v5.7.1**\n**Status:** the advisory (\"Unauthenticated Cross-Origin MCP Tool Invocation via Empty\nDefault Secret\") named three flaws. The fix (5.4.5) closed the **CORS** flaw\n(`Access-Control-Allow-Origin` is now set only for localhost origins), but left the\n**empty-default-secret** flaw the title is about: the SSE MCP server still defaults to an\nempty secret, `_isAuthorized()` still returns `true` when the secret is empty, and a\nnon-loopback bind only **warns**. So the server still runs **fully unauthenticated by\ndefault** — any non-browser caller (curl, SSRF, or a `0.0.0.0` bind) can invoke all 22 MCP\ntools (`config_set`, `agent_spawn`, `blackboard_write`, `token_*`) with no credentials.\n**Class:** CWE-306/CWE-862 Missing Authentication — incomplete fix.\n**Methodology:** M1 incomplete-fix audit (anchor = the 5.4.5 fix; sibling-walk on latest v5.7.1, executed).\n**Severity:** High (matches parent; the browser amplifier is removed, so exploitation now\nneeds non-browser reach — SSRF or a non-loopback bind, which the fix only warns about).\n\n## What the fix did and didn't do (verified on latest v5.7.1)\n| advisory flaw | latest v5.7.1 |\n|---|---|\n| wildcard CORS (`ACAO: *`) | **FIXED** — `lib/mcp-transport-sse.ts` sets `ACAO` only when `origin` matches `^https?://(localhost\\|127\\.0\\.0\\.1)(:\\d+)?$` |\n| empty default secret | **NOT FIXED** — `bin/mcp-server.ts`: `secret: process.env['NETWORK_AI_MCP_SECRET'] ?? ''` |\n| `_isAuthorized` open on empty secret | **NOT FIXED** — `if (!this._opts.secret) return true;` |\n| require secret / refuse unauth bind | **NOT DONE** — `listen()` only `process.stderr.write('… WARNING …')` on non-loopback bind, then listens anyway |\n\nThe advisory's remediation #1 (\"Require a non-empty secret at startup … `process.exit(1)`\")\nwas not implemented.\n\n## PoC (executed against the latest source, v5.7.1) — `poc/legend-networkai-empty-secret.ts`\nInstantiates the real `McpSseServer` from the latest `lib/` with a mock bridge and the\n**default (empty) secret**, then issues requests (run-log `poc/run-log.txt`):\n\n```\nPOST /mcp  no-auth, no-origin (curl/SSRF) -\u003e HTTP 200, dispatched=true\n   body: {\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"executed\":true,\"tool\":\"config_set\"}}\nPOST /mcp  Origin: evil.example.com        -\u003e ACAO=undefined   (CORS half fixed)\n```\nThe no-auth request passes `_isAuthorized` and reaches `handleRPC` (tool dispatched) — i.e.\nunauthenticated tool invocation persists on the latest release; only the browser-CORS read\namplifier was removed.\n\nRun: from a v5.7.1 checkout, `npm i` then\n`npx ts-node --transpile-only poc/legend-networkai-empty-secret.ts`.\n\n## Recommended fix\nImplement the advisory's remediation #1: refuse to start SSE mode with an empty secret\n(unless `--stdio`), and/or change `_isAuthorized` to fail closed (an empty configured\nsecret should mean \"deny\", not \"allow\"). The CORS allowlist alone does not authenticate\nnon-browser callers.\n\n## Precondition / honesty\nWith CORS now localhost-only, the drive-by *browser* attack is mitigated. The residual\nrequires a non-browser path to the port: an SSRF on the host, or the operator binding to a\nnon-loopback address (Docker/remote), which the fix only warns about. The empty secret\nremains the shipped default and `_isAuthorized` still authorizes it.\n\n## Credits\n\n@Kai Aizen / @SnailSploit — https://snailsploit.com","status":"published","published":"2026-06-19T13:34:24Z","modified":"2026-07-08T08:29:23.51958453Z","cvss":[{"version":"3.1","score":9.1,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N","level":"critical"}],"cwes":["CWE-306"],"updated_at":"2026-11-02T15:46:55.480549Z"}]}}
