# [CRIT] [GHSA / CRITICAL] CVE-2026-47393: PraisonAI `deploy --type api` emits a Flask server with authentication disabled by default

**Source:** GitHub Security Advisories
**Published:** 2026-05-29
**Article:** https://github.com/advisories/GHSA-8444-4fhq-fxpq

## Threat Profile

PraisonAI `deploy --type api` emits a Flask server with authentication disabled by default

### Summary

CVE-2026-44338 (GHSA-6rmh-7xcm-cpxj) documents that PraisonAI ships a code-generator (`praisonai.deploy.api.generate_api_server_code`) that emits a Flask API server with authentication disabled by default. Users who follow the documented quickstart (`praisonai deploy --type api`) get a server that:

- binds to `0.0.0.0` per the recommended sample YAML
- exposes `/chat` and `/agents` endpoints…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-47393`
- **CVE:** `CVE-2026-44338`
- **IPv4 (defanged):** `146.190.133.49`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1071** — Application Layer Protocol
- **T1204.002** — User Execution: Malicious File
- **T1133** — External Remote Services
- **T1059.006** — Command and Scripting Interpreter: Python
- **T1059.004** — Command and Scripting Interpreter: Unix Shell
- **T1105** — Ingress Tool Transfer

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### PraisonAI `deploy --type api` command execution — vulnerable server provisioned

`UC_167_3` · phase: **install** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=true count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as process values(Processes.parent_process_name) as parent_process_name from datamodel=Endpoint.Processes where (Processes.process="*praisonai*deploy*--type*api*" OR Processes.process="*praisonai*deploy*-t*api*") by Processes.dest Processes.user Processes.process_name | `drop_dm_object_name(Processes)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(30d)
| where ProcessCommandLine has "praisonai"
| where ProcessCommandLine has "deploy"
| where ProcessCommandLine has_any ("--type api", "-t api")
| project Timestamp, DeviceName, AccountName, AccountUpn, FolderPath, FileName,
          ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine,
          InitiatingProcessAccountName, SHA256
| order by Timestamp desc
```

### Public inbound to PraisonAI Flask listener on TCP/8005 (default port, 0.0.0.0 bind)

`UC_167_4` · phase: **delivery** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=true count min(_time) as firstTime max(_time) as lastTime values(All_Traffic.src) as src values(All_Traffic.dest) as dest from datamodel=Network_Traffic.All_Traffic where All_Traffic.dest_port=8005 All_Traffic.direction=inbound NOT (All_Traffic.src=10.0.0.0/8 OR All_Traffic.src=172.16.0.0/12 OR All_Traffic.src=192.168.0.0/16) by All_Traffic.dest All_Traffic.app | `drop_dm_object_name(All_Traffic)` | where count > 0 | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where LocalPort == 8005
| where ActionType in ("InboundConnectionAccepted", "ConnectionAcceptedInbound", "ConnectionSuccess")
| where RemoteIPType == "Public"
| where InitiatingProcessFileName in~ ("python.exe", "python3.exe", "python", "python3", "pythonw.exe")
   or InitiatingProcessCommandLine has_any ("praisonai", "api_server", "generate_api_server_code")
| project Timestamp, DeviceName, RemoteIP, RemotePort, LocalIP, LocalPort,
          InitiatingProcessFileName, InitiatingProcessCommandLine, InitiatingProcessAccountName
| order by Timestamp desc
```

### Unauthenticated POST to PraisonAI `/chat` or `/agents` endpoint (incl. CVE-Detector scanner)

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

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=true count min(_time) as firstTime max(_time) as lastTime values(Web.user_agent) as user_agent values(Web.src) as src from datamodel=Web.Web where (Web.url="*/chat*" OR Web.url="*/agents*") Web.http_method=POST by Web.dest Web.url Web.status | `drop_dm_object_name(Web)` | where (like(user_agent,"%CVE-Detector%") OR count > 5) | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
// Defender XDR has no native inbound HTTP table — detect via the Flask child shell instead (see UC4)
// If Defender for Endpoint web filtering ships URL telemetry to UrlClickEvents, we lose POST visibility, so this UC is best served by Sentinel/WAF/proxy logs
DeviceNetworkEvents
| where Timestamp > ago(7d)
| where LocalPort == 8005
| where ActionType in ("InboundConnectionAccepted", "ConnectionAcceptedInbound")
| where RemoteIPType == "Public"
| summarize Probes = count(), Sources = dcount(RemoteIP), SourceList = make_set(RemoteIP, 50)
          by DeviceName, bin(Timestamp, 5m)
| where Probes > 3 or Sources > 1
| order by Timestamp desc
```

### PraisonAI python process spawning shell, curl, or wget (post-exploitation tool-use abuse)

`UC_167_6` · phase: **actions** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats summariesonly=true count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as process from datamodel=Endpoint.Processes where Processes.parent_process="*praisonai*" (Processes.process_name="bash" OR Processes.process_name="sh" OR Processes.process_name="cmd.exe" OR Processes.process_name="powershell.exe" OR Processes.process_name="pwsh.exe" OR Processes.process_name="curl" OR Processes.process_name="curl.exe" OR Processes.process_name="wget" OR Processes.process_name="wget.exe") by Processes.dest Processes.user Processes.process_name Processes.parent_process_name | `drop_dm_object_name(Processes)` | convert ctime(firstTime) ctime(lastTime)
```

**Defender KQL:**
```kql
DeviceProcessEvents
| where Timestamp > ago(7d)
| where InitiatingProcessFileName in~ ("python.exe", "python3.exe", "python", "python3", "pythonw.exe")
| where InitiatingProcessCommandLine has_any ("praisonai", "api_server", "generate_api_server_code", "praisonai.run")
   or InitiatingProcessParentFileName in~ ("python.exe", "python3.exe", "python", "python3")
      and InitiatingProcessParentId in (
        (DeviceProcessEvents
         | where Timestamp > ago(7d)
         | where ProcessCommandLine has "praisonai" and ProcessCommandLine has "deploy"
         | distinct ProcessId)
      )
| where FileName in~ ("bash", "sh", "dash", "zsh", "cmd.exe", "powershell.exe", "pwsh.exe", "curl", "curl.exe", "wget", "wget.exe", "nc", "ncat", "socat")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, InitiatingProcessCommandLine,
          FileName, ProcessCommandLine, FolderPath, SHA256
| order by Timestamp desc
```

### Article-specific behavioural hunt — [GHSA / CRITICAL] CVE-2026-47393: PraisonAI `deploy --type api` emits a Flask se

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

**Splunk SPL (CIM):**
```spl
``` Article-specific bespoke detection — [GHSA / CRITICAL] CVE-2026-47393: PraisonAI `deploy --type api` emits a Flask se ```
| tstats `summariesonly` count earliest(_time) AS firstTime latest(_time) AS lastTime
    from datamodel=Endpoint.Processes
    where (Processes.process_name IN ("api.py"))
    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_path="*/usr/bin/env*" OR Filesystem.file_name IN ("api.py"))
    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-47393: PraisonAI `deploy --type api` emits a Flask se
// 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~ ("api.py"))
| 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 (FolderPath has_any ("/usr/bin/env") or FileName in~ ("api.py"))
| 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-47393`, `CVE-2026-44338`

- **Network connections to article IPs / domains** ([template](../_TEMPLATES.md#network-ioc)) — phase: **c2**, confidence: **High**
  - IP / domain IOC(s): `146.190.133.49`


## Why this matters

Severity classified as **CRIT** based on: CVE present, IOCs present, 7 use case(s) fired, 7 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.
