# PraisonAI vulnerable to unauthenticated arbitrary file read via MCP workflow.show, workflow.validate, deploy.validate

Incomplete fix left PraisonAI MCP handlers workflow.show/validate and deploy.validate path-unchecked, letting unauthenticated callers read any host file.

- Payout: Research
- Severity: high
- Program: PraisonAI
- Found by: beanduan22
- Disclosed: 2026-05-29
- CVE: CVE-2026-47394
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-9cr9-25q5-8prj
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-9cr9-25q5-8prj
- Tags: area:ai domain:ai domain:api impact:data-leak kind:research platform:ghsa sev:high tech:python technique:incomplete-fix technique:source-review vuln:access-control vuln:auth-bypass vuln:info-disclosure vuln:path-traversal

**Target:** MCP server tools/call handlers (cli_tools.py) over http-stream/stdio
**Root cause:** The dispatcher passes unvalidated JSON arguments as **kwargs to handlers without enforcing input_schema, and workflow.show/validate and deploy.validate never contain the user-supplied path. The prior patch only hardened rules.* handlers.
**Steps:**
1. Start server: `bash poc/start_mcp_server.sh` boots MCPServer on `127.0.0.1:8766/mcp` with `api_key=None` (no auth).
2. Send MCP `tools/call` for `praisonai.workflow.show` with `arguments: {"file_path": "<target>"}` via curl JSON-RPC.
3. Response `result.content[0].text` contains full file contents (e.g. `~/.ssh/id_rsa`, `~/.aws/credentials`, `.env`).
4. For `workflow.validate`/`deploy.validate`, pass arbitrary path; YAML parser error leaks existence and content fragments, e.g. `in "/etc/hosts", line 7, column 10`.
5. Repeat against `praisonai.audio.transcribe`, `files.create`, `ocr_extract` for OpenAI-backed exfil.
**How found:** Noticed the original advisory named four handlers but the patch commit 68cc9427 only added `_resolve_rule_path()` to rules.*; audited cli_tools.py for the same pattern and found workflow.show/validate and deploy.validate untouched, plus the dispatcher schema-enforcement gap still present at HEAD.
**Exploitation:** Unauthenticated MCP client (or prompt-injected LLM with attacker-controlled context) issues a single tools/call; handler opens the path as the praisonai host user and echoes contents back in the JSON-RPC response, yielding SSH keys, cloud creds, tokens.
**Escalation:** Read primitive alone yields credentials for lateral movement; original advisory's write primitive (rules.create) chained to RCE via .pth injection.
**Insight:** When a security advisory lists multiple vulnerable handlers, diff the fix commit against every named handler and grep the same file for sibling handlers with identical path-accepting signatures; incomplete fixes routinely miss adjacent tools and the shared dispatcher.

## Proof of concept (copied exactly from the original report)

**curl attack script run_mcp_poc_video.sh**

```
cd PraisonAI
bash poc/run_mcp_poc_video.sh
Six numbered steps. Each one prints the action, runs one `curl`, prints the JSON-RPC response.
```

**workflow.validate leaking /etc/hosts via YAML error**

```
{ "result": { "content": [{ "type": "text",
  "text": "YAML error: while scanning for the next token\nfound character '\\t' that cannot start any token\n  in \"/etc/hosts\", line 7, column 10" }] } }
```

