{"schema":"threatline.record/2","record":{"id":"CVE-2026-61427","aliases":["GHSA-hc5v-gxvj-58wh","PYSEC-2026-4257"],"summary":"PraisonAI: MCP HTTP-stream transport is unauthenticated by default, exposing tool enumeration and an unvalidated tool-call surface","details":"## Summary\n\nPraisonAI's MCP HTTP-stream server authenticates requests only when an API key is configured; the CLI defaults `--api-key` to `None`, so `praisonai mcp serve --transport http-stream` exposes the full MCP surface unauthenticated. A request with no `Authorization` (and no `Origin`) can `initialize` and `tools/list` (~50 tools), and the dispatcher forwards tool-call arguments to handlers without validating them against the advertised `inputSchema`. Runtime-confirmed for unauthenticated `initialize`/`tools/list` and the dispatcher schema-bypass. This is **not** an RCE/file-read in 4.6.63 — `workflow.run`/`workflow.run_file` are runtime-refuted (adapter regression). Severity Medium–High.\n\n## Details\n\n### Affected component\n- Package: `praisonai` 4.6.63. Files: `src/praisonai/praisonai/mcp_server/transports/http_stream.py`, `mcp_server/cli.py`, `mcp_server/server.py` (dispatcher).\n\n### Vulnerable code / root cause\n\nPath:\n`src/praisonai/praisonai/mcp_server/transports/http_stream.py`\n\nFunction:\n`mcp_post` / `_validate_origin`\n\nSnippet:\n```python\nif self.api_key:                       # auth applied ONLY when api_key is set\n    auth_header = request.headers.get(\"Authorization\", \"\")\n    if not auth_header.startswith(\"Bearer \") or auth_header[7:] != self.api_key:\n        return JSONResponse({\"error\": \"Unauthorized\"}, status_code=401)\n# _validate_origin: returns True when the Origin header is absent\n```\nIssue: with `api_key=None`, no auth check runs; a missing `Origin` header is allowed, so non-browser clients (curl/Burp) are not blocked.\n\nPath:\n`src/praisonai/praisonai/mcp_server/cli.py`\n\nFunction:\n`cmd_serve` (argparse)\n\nSnippet:\n```python\nparser.add_argument(\"--api-key\", default=None)   # unauthenticated by default\n```\n\nPath:\n`src/praisonai/praisonai/mcp_server/server.py`\n\nFunction:\n`_handle_tools_call`\n\nSnippet:\n```python\nresult = await tool.handler(**arguments)   # arguments forwarded without inputSchema validation\n```\nIssue: attacker-controlled `arguments` are passed straight to the handler; the dispatcher does not validate them against the tool's advertised `inputSchema`. The only thing rejecting undeclared keys is the handler's own Python signature.\n\n### Attack flow\n1. Operator runs `praisonai mcp serve --transport http-stream` (no `--api-key`).\n2. Attacker (no auth, no Origin) sends `initialize` → session; `tools/list` → enumerates ~50 tools; `tools/call` → arguments pass through unvalidated.\n\n### Why existing protection is bypassed\nAuth is opt-in (only added when an api key is set); missing `Origin` is allowed; the dispatcher does not enforce `inputSchema`.\n\n### Security boundary\nUnauthenticated access to the MCP tool surface. Default bind `127.0.0.1` (any local process / multi-user host; remote only if `--host 0.0.0.0`).\n\n### Scope limits (do not overclaim)\n- `praisonai.workflow.run` / `workflow.run_file` are **runtime-refuted in 4.6.63**: the adapter calls `AgentsGenerator(...)` missing the required `config_list` argument → errors before any execution/file open. Several other tool adapters also error at runtime. No unauthenticated RCE/arbitrary-file-open via these tools at HEAD.\n- MCP `knowledge.add` file read is broken (see `FT-01_Knowledge_FileRead_Negative_Report.md`).\n\n## Proof of Concept\n\n### Environment\nReal MCP HTTP-stream server (`api_key=None`) in a local runtime (`127.0.0.1:18090`). Runnable assets: `PraisonAI-Runtime-Repro\\runtime-files\\` (`docker-compose.mcp.yml`). MCP requests use `Accept: application/json` + header `Mcp-Session-Id`.\n\n### Steps to reproduce\n1. `MCP-Initialize`: `POST /mcp` initialize (no Authorization) → `200` + `mcp-session-id`.\n2. `MCP-Tools-List-NoAuth`: `POST /mcp` `tools/list` with that session id → `200` + ~50 tools.\n3. `MCP-Schema-Bypass`: `tools/call` with an undeclared extra argument (`__undeclared_evil_param__`).\n\n### Expected result\nThe transport requires authentication; the dispatcher validates arguments against `inputSchema`.\n\n### Actual result\n- `initialize`/`tools/list` succeed with no auth and no Origin header.\n- The undeclared argument reaches the handler (`got an unexpected keyword argument '__undeclared_evil_param__'`), proving no schema validation at the dispatcher.\n\n### Screenshots\n<img width=\"1544\" height=\"798\" alt=\"03-MCP-Schema-Bypass\" src=\"https://github.com/user-attachments/assets/5a4cb764-9428-487d-b4e0-2854cbda7fb7\" />\n<img width=\"1538\" height=\"793\" alt=\"02-MCP-Tools-List-NoAuth\" src=\"https://github.com/user-attachments/assets/6356af71-867f-4fbc-a994-c7ca338fd2aa\" />\n\n### Screenshots\n\n**Unauthenticated MCP initialize**\n\nA POST request to `/mcp` with method `initialize` succeeds without an `Authorization` header. The server returns HTTP 200 OK, exposes MCP capabilities, and issues an `mcp-session-id` to the unauthenticated client.\n\n<img width=\"1546\" height=\"804\" alt=\"01-MCP-Initialize-NoAuth\" src=\"https://github.com/user-attachments/assets/2a62ee6b-99d3-4a38-a752-bfe6165c8c04\" />\n\n**Unauthenticated MCP tools/list**\n\nAfter initialization, the same unauthenticated MCP session can call `tools/list` using only the issued `Mcp-Session-Id`. The server returns HTTP 200 OK and exposes tool names, schemas, and annotations.\n\n<img width=\"1538\" height=\"793\" alt=\"02-MCP-Tools-List-NoAuth\" src=\"https://github.com/user-attachments/assets/f55189ff-13aa-4c36-a617-3d2ee4a52a84\" />\n\n**MCP tool-call schema bypass**\n\nThe unauthenticated MCP client calls `tools/call` with an extra argument not declared in the tool schema. Instead of rejecting the schema-violating input at the dispatcher layer, the unexpected parameter reaches the Python handler and causes an `unexpected keyword argument` error. This confirms incomplete input-schema enforcement for tool calls.\n\n<img width=\"1544\" height=\"798\" alt=\"03-MCP-Schema-Bypass\" src=\"https://github.com/user-attachments/assets/d3f36e50-2363-4eb2-8b3c-985ff0e27f6e\" />\n\n## Impact\nUnauthenticated tool enumeration and tool-call surface; LLM-key/cost abuse and data access via whichever tools function (impact currently limited by several broken adapters and the default loopback bind). No confirmed unauthenticated RCE/file-read in 4.6.63.","categories":["Libraries & packages"],"product":"praisonai","vendor":"MervinPraison","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-hc5v-gxvj-58wh","source_modified_at":"2026-10-08T21:58:46Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"praisonai"},"range":"<= 4.6.77"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-61427","source_modified_at":"2026-07-16T15:18:17.077Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"PraisonAI","vendor":"MervinPraison","versions":[{"lessThan":"4.6.78","status":"affected","version":"0","versionType":"semver"},{"status":"unaffected","version":"4.6.78","versionType":"semver"}],"defaultStatus":"unaffected"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-hc5v-gxvj-58wh","source_modified_at":"2026-10-15T14:55:52.673558154Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"praisonai","ecosystem":"PyPI","purl":"pkg:pypi/praisonai"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.6.78"}]}],"versions":["0.0.1","0.0.10","0.0.11","0.0.12","0.0.13","0.0.14","0.0.15","0.0.16","0.0.17","0.0.18","0.0.19","0.0.2","0.0.20","0.0.21","0.0.22","0.0.23","0.0.24","0.0.25","0.0.26","0.0.27","0.0.28","0.0.29","0.0.3","0.0.30","0.0.31","0.0.32","0.0.33","0.0.34","0.0.35","0.0.36","0.0.37","0.0.38","0.0.39","0.0.4","0.0.40","0.0.41","0.0.42","0.0.43","0.0.44","0.0.45","0.0.46","0.0.47","0.0.48","0.0.49","0.0.5","0.0.50","0.0.52","0.0.53","0.0.54","0.0.55"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-hc5v-gxvj-58wh","source_modified_at":"2026-10-08T21:58:46Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"praisonai"},"version":"4.6.78"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-61427","source_modified_at":"2026-07-16T15:18:17.077Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"PraisonAI","ecosystem":null},"version":"4.6.78","basis":"first unaffected version stated in the CVE record"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-hc5v-gxvj-58wh","source_modified_at":"2026-10-15T14:55:52.673558154Z","fetched_at":"2026-10-23T18:48:36.087640Z","package":{"name":"praisonai","ecosystem":"PyPI","purl":"pkg:pypi/praisonai"},"version":"4.6.78"}],"cvss":7.3,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00389,"percentile":0.31802,"score_date":"2026-10-23"},"published_at":"2026-07-15T11:25:37.581Z","modified_at":"2026-10-15T14:55:52.673558154Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-hc5v-gxvj-58wh","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-08T21:58:46Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-61427","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-07-16T15:18:17.077Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-hc5v-gxvj-58wh","fetched_at":"2026-10-23T18:48:36.087640Z","source_modified_at":"2026-10-15T14:55:52.673558154Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-61427","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-hc5v-gxvj-58wh","tags":["exploit"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-61427","source":"GitHub Advisory Database"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-62178","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://www.vulncheck.com/advisories/praisonai-before-authentication-bypass-via-http-stream","tags":["third-party-advisory"]},{"url":"https://github.com/advisories/GHSA-hc5v-gxvj-58wh","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"yes","technical_impact":"partial","assessed_at":"2026-07-16T15:17:49.489510Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-15T14:55:52.673558154Z","content_hash":"3b1f33106fc3f26233a3f7fcc3080246c31befd416f4d02f736d7bbccb335add"}}
