---
id: CVE-2026-61427
aliases:
  - GHSA-hc5v-gxvj-58wh
title: >-
  PraisonAI: MCP HTTP-stream transport is unauthenticated by default, exposing
  tool enumeration and an unvalidated tool-call surface
summary: >-
  PraisonAI: MCP HTTP-stream transport is unauthenticated by default, exposing
  tool enumeration and an unvalidated tool-call surface
severity: high
cvss: 7.3
cwe:
  - CWE-20
  - CWE-306
  - CWE-862
vendor: praisonai
product: praisonai
ecosystem: pip
affected:
  - praisonai <= 4.6.77
patched:
  - praisonai 4.6.78
published: '2026-10-08'
updated: '2026-10-08'
sourceUpdated: '2026-10-08T21:58:46Z'
source: GHSA
sourceUrl: 'https://github.com/advisories/GHSA-hc5v-gxvj-58wh'
references:
  - url: >-
      https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-hc5v-gxvj-58wh
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-61427'
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-62178'
  - url: >-
      https://www.vulncheck.com/advisories/praisonai-before-authentication-bypass-via-http-stream
  - url: 'https://github.com/advisories/GHSA-hc5v-gxvj-58wh'
tags:
  - ghsa
  - pip
epss: 0.00389
epssPercentile: 0.30828
ingestedAt: '2026-10-08T22:11:53.878Z'
---

## Overview

## Summary

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: `praisonai` 4.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:
```python
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:
```python
parser.add_argument("--api-key", default=None)   # unauthenticated by default
```

Path:
`src/praisonai/praisonai/mcp_server/server.py`

Function:
`_handle_tools_call`

Snippet:
```python
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
1. Operator runs `praisonai mcp serve --transport http-stream` (no `--api-key`).
2. 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_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.
- MCP `knowledge.add` file read is broken (see `FT-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
1. `MCP-Initialize`: `POST /mcp` initialize (no Authorization) → `200` + `mcp-session-id`.
2. `MCP-Tools-List-NoAuth`: `POST /mcp` `tools/list` with that session id → `200` + ~50 tools.
3. `MCP-Schema-Bypass`: `tools/call` with an undeclared extra argument (`__undeclared_evil_param__`).

### Expected result
The transport requires authentication; the dispatcher validates arguments against `inputSchema`.

### Actual result
- `initialize`/`tools/list` succeed 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
<img width="1544" height="798" alt="03-MCP-Schema-Bypass" src="https://github.com/user-attachments/assets/5a4cb764-9428-487d-b4e0-2854cbda7fb7" />
<img width="1538" height="793" alt="02-MCP-Tools-List-NoAuth" src="https://github.com/user-attachments/assets/6356af71-867f-4fbc-a994-c7ca338fd2aa" />

### 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.

<img width="1546" height="804" alt="01-MCP-Initialize-NoAuth" src="https://github.com/user-attachments/assets/2a62ee6b-99d3-4a38-a752-bfe6165c8c04" />

**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.

<img width="1538" height="793" alt="02-MCP-Tools-List-NoAuth" src="https://github.com/user-attachments/assets/f55189ff-13aa-4c36-a617-3d2ee4a52a84" />

**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.

<img width="1544" height="798" alt="03-MCP-Schema-Bypass" src="https://github.com/user-attachments/assets/d3f36e50-2363-4eb2-8b3c-985ff0e27f6e" />

## 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 packages

- `praisonai <= 4.6.77`

## Remediation

Upgrade to a patched release:

- `praisonai 4.6.78`
