Every CVE Search/ Get API key

CVE-2026-61438

PraisonAI before 4.6.78 Remote Code Execution via Broken AST Sandbox

7.0 HighFix available

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
Low
User interaction
Passive

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.31%Up 0.1 points since Jul 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.0

PraisonAI before 4.6.78 Remote Code Execution via Broken AST Sandbox

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Record
CVE-2026-61438
CVSS 4.0
7.0 HighCVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
CVSS 3.1
7.3 HighCVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78
Updated
2026-11-02
EUVDEUVD-2026-44643 7.0

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Record
EUVD-2026-44643
CVSS 4.0
7.0 HighCVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-26mh-57q7-jfvr 7.3

PraisonAI vulnerable to Remote Code Execution via Broken AST Sandbox

Summary

JobWorkflowExecutor._exec_inline_python() is designed to safely execute inline Python expressions from YAML workflow script: steps using AST validation. The function claims to block dangerous operations by (a) checking all AST nodes against an allowlist, and (b) providing a builtins whitelist that omits import, exec, eval, and open.

The sandbox is broken. The module import allowlist (allowed_modules) explicitly includes 'os', and the AST allowlist permits ast.Import, ast.ImportFrom, ast.Call, and ast.Attribute nodes. This means the following malicious workflow script: step passes all AST validation checks and executes without error.

Attack Scenario

Attacker creates or contributes a YAML workflow file (type: job) with a script: step containing import os; os.system(...). A user or CI pipeline with PRAISONAI_ALLOW_JOB_WORKFLOWS=true executes the workflow via praisonai workflow run malicious.yaml. Arbitrary OS commands execute with the privileges of the calling process.

This is particularly dangerous in multi-tenant or CI environments where YAML workflows may originate from untrusted sources (e.g., downloaded templates, shared repositories, AI-generated workflows).

PoC

Complete instructions, including specific configuration details, to reproduce the vulnerability.

Impact

Root Cause — Lines 364–372:

pythonallowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'} if isinstance(node, ast.Import): for alias in node.names: if alias.name.split('.')[0] not in allowed_modules: return {"ok": False, "error": f"Import of '{alias.name}' not allowed..."}

os is trusted because it is commonly used for path operations (os.path, os.getcwd). However, os.system(), os.popen(), os.execvp(), os.spawn*(), and os._exit() are all accessible once the module is imported, none of which are individually blocked.

The builtins restriction (blocking import) is irrelevant because the code uses a real import statement processed by the Python bytecode compiler — not a import() call.

Proof-of-Concept validation (static — no remote network call made):

pythonimport ast

_ALLOWED_NODES = ( ast.Expression, ast.BoolOp, ast.BinOp, ast.UnaryOp, ast.Compare, ast.IfExp, ast.Constant, ast.Name, ast.Load, ast.Store, ast.Subscript, ast.List, ast.Tuple, ast.Dict, ast.Set, ast.And, ast.Or, ast.Not, ast.Eq, ast.NotEq, ast.Lt, ast.LtE, ast.Gt, ast.GtE, ast.In, ast.NotIn, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod, ast.FloorDiv, ast.USub, ast.UAdd, ast.Call, ast.Attribute, ast.keyword, ast.Starred, ast.Module, ast.Assign, ast.Import, ast.ImportFrom, ast.alias, ) allowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'}

malicious = "import os\nresult = os.system('id')" tree = ast.parse(malicious, mode="exec")

all_pass = True for node in ast.walk(tree): if not isinstance(node, _ALLOWED_NODES): print(f"BLOCKED: {type(node).name}") all_pass = False if isinstance(node, ast.Import): for alias in node.names: if alias.name.split('.')[0] not in allowed_modules: print(f"IMPORT BLOCKED: {alias.name}") all_pass = False

print("SANDBOX BYPASSED" if all_pass else "sandbox holds")

Output: SANDBOX BYPASSED

Recommended Fix

Remove 'os' from allowed_modules and replace it with only the safe submodule: 'os.path'. Then validate that the imported name is specifically os.path, not os:

python# BEFORE (vulnerable) allowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'}

AFTER (safe)

allowed_modules = {'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools', 'pathlib'}

If os.path is needed, handle it explicitly:

if isinstance(node, ast.ImportFrom): if node.module == 'os.path': pass # allow 'from os.path import join, exists' only elif node.module and…

Record
GHSA-26mh-57q7-jfvr
CVSS 3.1
7.3 HighCVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78, CWE-184, CWE-693
Updated
2026-11-02
GitHub AdvisoriesGHSA-qh3g-555w-f82q 7.0

Duplicate Advisory: PraisonAI vulnerable to Remote Code Execution via Broken AST Sandbox

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-26mh-57q7-jfvr. This link is maintained to preserve external references.

Original Description

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Record
GHSA-qh3g-555w-f82q
CVSS 4.0
7.0 HighCVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.3 HighCVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78
Updated
2026-11-02
NVD 7.0

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Record
CVE-2026-61438
CVSS 4.0
7.0 HighCVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.3 HighCVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78
Updated
2026-11-02
OSV 7.0

PraisonAI before 4.6.78 Remote Code Execution via Broken AST Sandbox

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Record
CVE-2026-61438
CVSS 4.0
7.0 HighCVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N
Weakness
CWE-78
Updated
2026-11-02
OSVGHSA-26mh-57q7-jfvr 7.3

PraisonAI vulnerable to Remote Code Execution via Broken AST Sandbox

Summary

JobWorkflowExecutor._exec_inline_python() is designed to safely execute inline Python expressions from YAML workflow script: steps using AST validation. The function claims to block dangerous operations by (a) checking all AST nodes against an allowlist, and (b) providing a builtins whitelist that omits import, exec, eval, and open.

The sandbox is broken. The module import allowlist (allowed_modules) explicitly includes 'os', and the AST allowlist permits ast.Import, ast.ImportFrom, ast.Call, and ast.Attribute nodes. This means the following malicious workflow script: step passes all AST validation checks and executes without error.

Attack Scenario

Attacker creates or contributes a YAML workflow file (type: job) with a script: step containing import os; os.system(...). A user or CI pipeline with PRAISONAI_ALLOW_JOB_WORKFLOWS=true executes the workflow via praisonai workflow run malicious.yaml. Arbitrary OS commands execute with the privileges of the calling process.

This is particularly dangerous in multi-tenant or CI environments where YAML workflows may originate from untrusted sources (e.g., downloaded templates, shared repositories, AI-generated workflows).

PoC

Complete instructions, including specific configuration details, to reproduce the vulnerability.

Impact

Root Cause — Lines 364–372:

pythonallowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'} if isinstance(node, ast.Import): for alias in node.names: if alias.name.split('.')[0] not in allowed_modules: return {"ok": False, "error": f"Import of '{alias.name}' not allowed..."}

os is trusted because it is commonly used for path operations (os.path, os.getcwd). However, os.system(), os.popen(), os.execvp(), os.spawn*(), and os._exit() are all accessible once the module is imported, none of which are individually blocked.

The builtins restriction (blocking import) is irrelevant because the code uses a real import statement processed by the Python bytecode compiler — not a import() call.

Proof-of-Concept validation (static — no remote network call made):

pythonimport ast

_ALLOWED_NODES = ( ast.Expression, ast.BoolOp, ast.BinOp, ast.UnaryOp, ast.Compare, ast.IfExp, ast.Constant, ast.Name, ast.Load, ast.Store, ast.Subscript, ast.List, ast.Tuple, ast.Dict, ast.Set, ast.And, ast.Or, ast.Not, ast.Eq, ast.NotEq, ast.Lt, ast.LtE, ast.Gt, ast.GtE, ast.In, ast.NotIn, ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Mod, ast.FloorDiv, ast.USub, ast.UAdd, ast.Call, ast.Attribute, ast.keyword, ast.Starred, ast.Module, ast.Assign, ast.Import, ast.ImportFrom, ast.alias, ) allowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'}

malicious = "import os\nresult = os.system('id')" tree = ast.parse(malicious, mode="exec")

all_pass = True for node in ast.walk(tree): if not isinstance(node, _ALLOWED_NODES): print(f"BLOCKED: {type(node).name}") all_pass = False if isinstance(node, ast.Import): for alias in node.names: if alias.name.split('.')[0] not in allowed_modules: print(f"IMPORT BLOCKED: {alias.name}") all_pass = False

print("SANDBOX BYPASSED" if all_pass else "sandbox holds")

Output: SANDBOX BYPASSED

Recommended Fix

Remove 'os' from allowed_modules and replace it with only the safe submodule: 'os.path'. Then validate that the imported name is specifically os.path, not os:

python# BEFORE (vulnerable) allowed_modules = {'os', 'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools'}

AFTER (safe)

allowed_modules = {'datetime', 'time', 'json', 'math', 're', 'collections', 'itertools', 'pathlib'}

If os.path is needed, handle it explicitly:

if isinstance(node, ast.ImportFrom): if node.module == 'os.path': pass # allow 'from os.path import join, exists' only elif node.module and…

Record
GHSA-26mh-57q7-jfvr
CVSS 3.1
7.3 HighCVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-184, CWE-693, CWE-78
Updated
2026-11-02
OSVGHSA-qh3g-555w-f82q 7.0

Duplicate Advisory: PraisonAI vulnerable to Remote Code Execution via Broken AST Sandbox

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-26mh-57q7-jfvr. This link is maintained to preserve external references.

Original Description

PraisonAI before 4.6.78 contains a remote code execution vulnerability in JobWorkflowExecutor._exec_inline_python() due to insufficient AST validation of workflow script steps. Attackers can create malicious YAML workflow files with import os statements followed by os.system() calls that bypass sandbox checks and execute arbitrary OS commands with process privileges.

Record
GHSA-qh3g-555w-f82q
CVSS 4.0
7.0 HighCVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
7.3 HighCVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H
Weakness
CWE-78
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
praisonai
PyPI
before 4.6.78
4.6.78
praisonai
PyPI
before 4.6.78, plus listed versions
0.0.10.0.100.0.110.0.120.0.13
Show 45 moreShow less
0.0.140.0.150.0.160.0.170.0.180.0.190.0.20.0.200.0.210.0.220.0.230.0.240.0.250.0.260.0.270.0.280.0.290.0.30.0.300.0.310.0.320.0.330.0.340.0.350.0.360.0.370.0.380.0.390.0.40.0.400.0.410.0.420.0.430.0.440.0.450.0.460.0.470.0.480.0.490.0.50.0.500.0.520.0.530.0.540.0.55
4.6.78

History

History
RecordedChangedSources
affected
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-61438 is a high vulnerability (CVSS 7.0) in Mervinpraison Praisonai, published July 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.31%, the 24th percentile. Fixed in praisonai 4.6.78.

References

This page doesn't list everything

Left out here: 713 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open