GHSA-HC5V-GXVJ-58WH
Vulnerability from github – Published: 2026-10-08 21:58 – Updated: 2026-10-08 21:58Summary
PraisonAI'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.
Details
Affected component
- Package:
praisonai4.6.63. Files:src/praisonai/praisonai/mcp_server/transports/http_stream.py,mcp_server/cli.py,mcp_server/server.py(dispatcher).
Vulnerable code / root cause
Path:
src/praisonai/praisonai/mcp_server/transports/http_stream.py
Function:
mcp_post / _validate_origin
Snippet:
if self.api_key: # auth applied ONLY when api_key is set
auth_header = request.headers.get("Authorization", "")
if not auth_header.startswith("Bearer ") or auth_header[7:] != self.api_key:
return JSONResponse({"error": "Unauthorized"}, status_code=401)
# _validate_origin: returns True when the Origin header is absent
Issue: with api_key=None, no auth check runs; a missing Origin header is allowed, so non-browser clients (curl/Burp) are not blocked.
Path:
src/praisonai/praisonai/mcp_server/cli.py
Function:
cmd_serve (argparse)
Snippet:
parser.add_argument("--api-key", default=None) # unauthenticated by default
Path:
src/praisonai/praisonai/mcp_server/server.py
Function:
_handle_tools_call
Snippet:
result = await tool.handler(**arguments) # arguments forwarded without inputSchema validation
Issue: 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.
Attack flow
- Operator runs
praisonai mcp serve --transport http-stream(no--api-key). - Attacker (no auth, no Origin) sends
initialize→ session;tools/list→ enumerates ~50 tools;tools/call→ arguments pass through unvalidated.
Why existing protection is bypassed
Auth is opt-in (only added when an api key is set); missing Origin is allowed; the dispatcher does not enforce inputSchema.
Security boundary
Unauthenticated 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).
Scope limits (do not overclaim)
praisonai.workflow.run/workflow.run_fileare runtime-refuted in 4.6.63: the adapter callsAgentsGenerator(...)missing the requiredconfig_listargument → 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.- MCP
knowledge.addfile read is broken (seeFT-01_Knowledge_FileRead_Negative_Report.md).
Proof of Concept
Environment
Real 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.
Steps to reproduce
MCP-Initialize:POST /mcpinitialize (no Authorization) →200+mcp-session-id.MCP-Tools-List-NoAuth:POST /mcptools/listwith that session id →200+ ~50 tools.MCP-Schema-Bypass:tools/callwith an undeclared extra argument (__undeclared_evil_param__).
Expected result
The transport requires authentication; the dispatcher validates arguments against inputSchema.
Actual result
initialize/tools/listsucceed with no auth and no Origin header.- The undeclared argument reaches the handler (
got an unexpected keyword argument '__undeclared_evil_param__'), proving no schema validation at the dispatcher.
Screenshots
Screenshots
Unauthenticated MCP initialize
A 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.
Unauthenticated MCP tools/list
After 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.
MCP tool-call schema bypass
The 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.
Impact
Unauthenticated 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.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.6.77"
},
"package": {
"ecosystem": "PyPI",
"name": "praisonai"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.6.78"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61427"
],
"database_specific": {
"cwe_ids": [
"CWE-20",
"CWE-306",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-08T21:58:42Z",
"nvd_published_at": "2026-07-15T17:16:52Z",
"severity": "HIGH"
},
"details": "## Summary\n\nPraisonAI\u0027s 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 \u2014 `workflow.run`/`workflow.run_file` are runtime-refuted (adapter regression). Severity Medium\u2013High.\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\u0027s advertised `inputSchema`. The only thing rejecting undeclared keys is the handler\u0027s 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` \u2192 session; `tools/list` \u2192 enumerates ~50 tools; `tools/call` \u2192 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 \u2192 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) \u2192 `200` + `mcp-session-id`.\n2. `MCP-Tools-List-NoAuth`: `POST /mcp` `tools/list` with that session id \u2192 `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 \u0027__undeclared_evil_param__\u0027`), proving no schema validation at the dispatcher.\n\n### Screenshots\n\u003cimg width=\"1544\" height=\"798\" alt=\"03-MCP-Schema-Bypass\" src=\"https://github.com/user-attachments/assets/5a4cb764-9428-487d-b4e0-2854cbda7fb7\" /\u003e\n\u003cimg width=\"1538\" height=\"793\" alt=\"02-MCP-Tools-List-NoAuth\" src=\"https://github.com/user-attachments/assets/6356af71-867f-4fbc-a994-c7ca338fd2aa\" /\u003e\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\u003cimg width=\"1546\" height=\"804\" alt=\"01-MCP-Initialize-NoAuth\" src=\"https://github.com/user-attachments/assets/2a62ee6b-99d3-4a38-a752-bfe6165c8c04\" /\u003e\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\u003cimg width=\"1538\" height=\"793\" alt=\"02-MCP-Tools-List-NoAuth\" src=\"https://github.com/user-attachments/assets/f55189ff-13aa-4c36-a617-3d2ee4a52a84\" /\u003e\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\u003cimg width=\"1544\" height=\"798\" alt=\"03-MCP-Schema-Bypass\" src=\"https://github.com/user-attachments/assets/d3f36e50-2363-4eb2-8b3c-985ff0e27f6e\" /\u003e\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.",
"id": "GHSA-hc5v-gxvj-58wh",
"modified": "2026-10-08T21:58:42Z",
"published": "2026-10-08T21:58:42Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-hc5v-gxvj-58wh"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-61427"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-62178"
},
{
"type": "PACKAGE",
"url": "https://github.com/MervinPraison/PraisonAI"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/praisonai-before-authentication-bypass-via-http-stream"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
}
],
"summary": "PraisonAI: MCP HTTP-stream transport is unauthenticated by default, exposing tool enumeration and an unvalidated tool-call surface"
}
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.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
Related by attack behaviour
Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.