PT-2026-45051 · Pypi · Praisonai+1

Publicado

2026-05-29

·

Atualizado

2026-05-29

·

CVE-2026-47392

CVSS v3.1

9.9

Crítica

VetorAV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H

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) ...
', 'stderr': '', 'success': True}

Step-by-step bypass analysis:

LineAST nodeCheckResult
print. self Attribute(attr=' self ')self in blocked attrs?NO → passes
b.varsAttribute(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]SubscriptNot checkedpasses
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

Correção

Protection Mechanism Failure

Incomplete List of Disallowed Inputs

Encontrou algum problema na descrição? Tem algo a acrescentar? Fique à vontade para nos escrever 👾

Enumeração de Fraquezas

Identificadores relacionados

CVE-2026-47392
GHSA-4MR5-G6F9-CFRH

Produtos afetados

Praisonai
Praisonaiagents