# [CRIT] [GHSA / CRITICAL] CVE-2026-47392: PraisonAI vulnerable to sandbox escape via `print.__self__` builtins module leak in `execute_code` (subprocess mode)

**Source:** GitHub Security Advisories
**Published:** 2026-05-29
**Article:** https://github.com/advisories/GHSA-4mr5-g6f9-cfrh

## Threat Profile

PraisonAI vulnerable to sandbox escape via `print.__self__` builtins module leak in `execute_code` (subprocess mode)

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

Thi…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-47392`
- **CVE:** `CVE-2026-39888`
- **CVE:** `CVE-2026-34938`
- **CVE:** `CVE-2026-40158`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1566.001** — Spearphishing Attachment
- **T1204.002** — User Execution: Malicious File
- **T1059.001** — PowerShell
- **T1059.005** — Visual Basic
- **T1218** — System Binary Proxy Execution
- **T1059.006** — Command and Scripting Interpreter: Python
- **T1059.004** — Command and Scripting Interpreter: Unix Shell
- **T1068** — Exploitation for Privilege Escalation
- **T1552.001** — Credentials In Files
- **T1027** — Obfuscated Files or Information

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### Vulnerable PraisonAI package (≤1.6.39) installed on managed host

`UC_166_4` · phase: **weapon** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count from datamodel=Vulnerabilities.Vulnerabilities where Vulnerabilities.cve IN ("CVE-2026-47392","CVE-2026-39888","CVE-2026-34938","CVE-2026-40158") by Vulnerabilities.dest Vulnerabilities.signature Vulnerabilities.cve Vulnerabilities.cvss Vulnerabilities.severity Vulnerabilities.vendor_product
| `drop_dm_object_name("Vulnerabilities")`
| rename dest as host
| sort - cvss
```

**Defender KQL:**
```kql
DeviceTvmSoftwareInventory
| where Timestamp > ago(1d)
| where SoftwareName has_any ("praisonaiagents", "praisonai")
| extend ParsedVersion = parse_version(SoftwareVersion)
| where ParsedVersion <= parse_version("1.6.39")
| project DeviceId, DeviceName, OSPlatform, SoftwareVendor, SoftwareName, SoftwareVersion, EndOfSupportStatus
| join kind=leftouter (
    DeviceInfo
    | where Timestamp > ago(1d)
    | summarize arg_max(Timestamp, PublicIP, IsInternetFacing, MachineGroup) by DeviceId
  ) on DeviceId
| order by IsInternetFacing desc, DeviceName asc
```

### PraisonAI Python subprocess spawns OS shell with discovery / credential-reading commands

`UC_166_5` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as cmdline from datamodel=Endpoint.Processes where (Processes.parent_process_name IN ("python","python.exe","python3","python3.exe","python3.10","python3.11","python3.12") OR Processes.parent_process IN ("*python*","*python3*")) (Processes.process_name IN ("sh","bash","dash","zsh","cmd.exe","powershell.exe","pwsh.exe") OR Processes.process IN ("*/bin/sh*","*/bin/bash*")) (Processes.process="*praisonai*" OR Processes.parent_process="*praisonai*" OR Processes.parent_process="*execute_code*" OR Processes.parent_process="*python_tools*" OR Processes.process="* id*" OR Processes.process="*whoami*" OR Processes.process="*uname -a*" OR Processes.process="*/proc/self/environ*" OR Processes.process="*cat /etc/passwd*" OR Processes.process="*cat /etc/shadow*" OR Processes.process="*AWS_SECRET*" OR Processes.process="*AWS_ACCESS_KEY*" OR Processes.process="*AZURE_CLIENT_SECRET*" OR Processes.process="*OPENAI_API_KEY*" OR Processes.process="*/run/secrets*" OR Processes.process="*printenv*") by host Processes.user Processes.parent_process Processes.process_name Processes.process Processes.parent_process_id Processes.process_id
| `drop_dm_object_name("Processes")`
| convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
let praisonContext = DeviceProcessEvents
  | where Timestamp > ago(7d)
  | where FileName in~ ("python","python3","python.exe","python3.exe","python3.10","python3.11","python3.12")
  | where ProcessCommandLine has_any ("praisonai", "_execute_code_sandboxed", "python_tools.py", "execute_code")
     or InitiatingProcessFolderPath has "praisonai"
     or FolderPath has "praisonai"
  | project ParentDeviceId=DeviceId, ParentProcessId=ProcessId, ParentTime=Timestamp, ParentCmd=ProcessCommandLine, ParentFolder=FolderPath;
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("python","python3","python.exe","python3.exe","python3.10","python3.11","python3.12")
| where FileName in~ ("sh","bash","dash","zsh","cmd.exe","powershell.exe","pwsh.exe")
| where ProcessCommandLine has_any ("id","whoami","uname -a","hostname","cat /etc/passwd","cat /etc/shadow","/proc/self/environ","printenv","env | ","AWS_SECRET","AWS_ACCESS_KEY","AZURE_CLIENT_SECRET","GCP_SERVICE_ACCOUNT","OPENAI_API_KEY","ANTHROPIC_API_KEY","/run/secrets","/var/run/secrets","kubectl ","curl http","wget http","nc -e","bash -i","/dev/tcp/")
| where AccountName !endswith "$"
| join kind=inner praisonContext on $left.InitiatingProcessId == $right.ParentProcessId and $left.DeviceId == $right.ParentDeviceId
| project Timestamp, DeviceName, AccountName, ParentCmd, InitiatingProcessFileName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, FolderPath, ParentFolder
| order by Timestamp desc
```

### Literal PraisonAI sandbox-escape signature: `print.__self__` + builtins dict access

`UC_166_6` · phase: **exploit** · confidence: **Medium** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime from datamodel=Endpoint.Processes where Processes.process_name IN ("python","python.exe","python3","python3.exe","python3.10","python3.11","python3.12") (Processes.process="*print.__self__*" OR Processes.process="*__self__*vars(*" OR Processes.process="*vars(print*" OR Processes.process="*.__self__.vars*") by host Processes.user Processes.parent_process Processes.process_name Processes.process Processes.process_id
| `drop_dm_object_name("Processes")`
| convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
union
(
  DeviceProcessEvents
  | where Timestamp > ago(7d)
  | where FileName in~ ("python","python3","python.exe","python3.exe","python3.10","python3.11","python3.12")
  | where ProcessCommandLine has_any ("print.__self__", ".__self__.vars", "vars(print", "__self__\nd")
     or ProcessCommandLine matches regex @"print\s*\.\s*__self__"
  | extend Source = "cmdline"
  | project Timestamp, Source, DeviceName, AccountName, FileName, ProcessCommandLine, FolderPath, InitiatingProcessCommandLine
),
(
  DeviceFileEvents
  | where Timestamp > ago(7d)
  | where ActionType in ("FileCreated","FileModified")
  | where FileName endswith ".py"
     or FolderPath has_any ("/tmp/", @"\Temp\", "/var/folders/")
  | where InitiatingProcessFileName in~ ("python","python3","python.exe","python3.exe")
  | where InitiatingProcessCommandLine has_any ("praisonai","_execute_code_sandboxed","python_tools","execute_code")
  | extend Source = "file-write"
  | project Timestamp, Source, DeviceName, AccountName=InitiatingProcessAccountName, FileName, FolderPath, InitiatingProcessCommandLine, ProcessCommandLine=""
)
| order by Timestamp desc
```

### Email attachment opened from external sender

`UC_PHISH_ATTACH` · phase: **delivery** · confidence: **High**

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count
    from datamodel=Email.All_Email
    where All_Email.file_name!="-"
    by All_Email.src_user, All_Email.recipient, All_Email.file_name, All_Email.subject
| rename All_Email.recipient as user
| join type=inner user
    [| tstats `summariesonly` count
        from datamodel=Endpoint.Processes
        where Processes.parent_process_name IN ("OUTLOOK.EXE","winword.exe","excel.exe","powerpnt.exe")
          AND Processes.process_name IN ("cmd.exe","powershell.exe","wscript.exe","cscript.exe","mshta.exe","rundll32.exe","regsvr32.exe")
        by Processes.dest, Processes.user, Processes.parent_process_name, Processes.process_name, Processes.process
     | rename Processes.user as user]
```

**Defender KQL:**
```kql
let LookbackDays = 7d;
let MalAttachments = EmailAttachmentInfo
    | where Timestamp > ago(LookbackDays)
    | where AccountName !endswith "$"
    | project NetworkMessageId, RecipientEmailAddress,
              AttachmentFileName = FileName, AttachmentSHA256 = SHA256;
DeviceProcessEvents
| where Timestamp > ago(LookbackDays)
| where InitiatingProcessFileName in~ ("OUTLOOK.EXE","winword.exe","excel.exe","powerpnt.exe")
| where FileName in~ ("cmd.exe","powershell.exe","wscript.exe","cscript.exe",
                      "mshta.exe","rundll32.exe","regsvr32.exe")
| join kind=inner MalAttachments on $left.AccountUpn == $right.RecipientEmailAddress
| project Timestamp, DeviceName, AccountName, FileName, ProcessCommandLine,
          InitiatingProcessFileName, AttachmentFileName, AttachmentSHA256
```

### Office app spawning script/LOLBin child process

`UC_OFFICE_CHILD` · phase: **exploit** · confidence: **High**

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime
    from datamodel=Endpoint.Processes
    where Processes.parent_process_name IN ("winword.exe","excel.exe","powerpnt.exe","outlook.exe","onenote.exe","mspub.exe","visio.exe")
      AND Processes.process_name IN ("cmd.exe","powershell.exe","pwsh.exe","wscript.exe","cscript.exe","mshta.exe","rundll32.exe","regsvr32.exe","wmic.exe","bitsadmin.exe","certutil.exe")
    by Processes.dest, Processes.user, Processes.parent_process_name, Processes.process_name, Processes.process
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where AccountName !endswith "$"
| where InitiatingProcessFileName in~ ("winword.exe","excel.exe","powerpnt.exe","outlook.exe","onenote.exe","mspub.exe","visio.exe")
| where FileName in~ ("cmd.exe","powershell.exe","pwsh.exe","wscript.exe","cscript.exe","mshta.exe","rundll32.exe","regsvr32.exe","wmic.exe","bitsadmin.exe","certutil.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, FileName, ProcessCommandLine
```

### Article-specific behavioural hunt — [GHSA / CRITICAL] CVE-2026-47392: PraisonAI vulnerable to sandbox escape via `pr

`UC_166_3` · phase: **exploit** · confidence: **High**

**Splunk SPL (CIM):**
```spl
``` Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-47392: PraisonAI vulnerable to sandbox escape via `pr ```
| tstats `summariesonly` count earliest(_time) AS firstTime latest(_time) AS lastTime
    from datamodel=Endpoint.Processes
    where (Processes.process_name IN ("node.js"))
    by Processes.dest, Processes.user, Processes.process_name,
       Processes.process, Processes.parent_process_name, Processes.process_path
| `drop_dm_object_name(Processes)`
| `security_content_ctime(firstTime)`
| append [
| tstats `summariesonly` count
    from datamodel=Endpoint.Filesystem
    where Filesystem.action IN ("created","modified")
      AND (Filesystem.file_name IN ("node.js"))
    by Filesystem.dest, Filesystem.user, Filesystem.process_name,
       Filesystem.file_path, Filesystem.file_name
| `drop_dm_object_name(Filesystem)`
]
```

**Defender KQL:**
```kql
// Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-47392: PraisonAI vulnerable to sandbox escape via `pr
// Hunts the actual binaries / paths / commandline fragments named
// in the article instead of a generic technique-class template.
DeviceProcessEvents
| where Timestamp > ago(30d)
| where (FileName in~ ("node.js"))
| project Timestamp, DeviceName, AccountName, FileName,
          FolderPath, ProcessCommandLine,
          InitiatingProcessFileName, InitiatingProcessCommandLine
| order by Timestamp desc

// File-creation events for the named binaries / paths
DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in ("FileCreated","FileModified")
| where (FileName in~ ("node.js"))
| project Timestamp, DeviceName, AccountName, FolderPath,
          FileName, ActionType, InitiatingProcessFileName,
          InitiatingProcessCommandLine
| order by Timestamp desc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-47392`, `CVE-2026-39888`, `CVE-2026-34938`, `CVE-2026-40158`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 7 use case(s) fired, 11 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
